1#![feature(once_cell_get_mut)]
22#![feature(macro_metavar_expr)]
23#![feature(str_as_str)]
24#![feature(random)]
25extern crate core;
26
27pub mod api;
28pub mod components;
29pub mod css;
30pub mod pages;
31pub mod utils;
32pub mod js;
33
34pub use app::*;
35pub use utils::*;
36
37#[cfg(test)]
41mod tests {
42 use crate::components::app::css::css;
43 use crate::components::sanitize::sanitized;
44 use crate::components::title::title;
45 use crate::defaults::{PARAMS_ID, PARAMS_TITLE};
46 use crate::jobs::JobResult;
47 use crate::testdata::data::{create_test_form, RAW_HTML_PREFORMATTED, TESTDATA_EXPECTED_FORMDATA, TESTDATA_EXPECTED_FORMDATA_EMPTY, TESTDATA_FORMDATA_EMPTY_REQUEST, TESTDATA_FORMDATA_EMPTY_REQUEST_WITH_BOUNDARIES, TESTDATA_FORMDATA_REQUEST, TRIMMED_HTML_PREFORMATTED, TRIMMED_HTML_RENDER_CSS, TRIMMED_HTML_TITLE_RENDER};
48 use crate::{rumtk_web_get_job_manager, rumtk_web_init_job_manager, rumtk_web_params_map, rumtk_web_post_process, rumtk_web_register_app_components, rumtk_web_register_app_switches, rumtk_web_render, rumtk_web_render_component, rumtk_web_render_redirect, rumtk_web_run_app, rumtk_web_sync_get, rumtk_web_trim_rendered_html, sanitize_html, AppState, RUMWebData, RUMWebRedirect, RenderedPageComponentsResult, SharedAppState};
49 use crate::{RUMWebResponse, RUMWebTemplate};
50 use rand::random;
51 use rumtk_core::buffers::buffer_to_str;
52 use rumtk_core::strings::{rumtk_format, RUMString};
53 use rumtk_core::{rumtk_new_lock, rumtk_sleep};
54 use std::thread::spawn;
55
56
57 const EXPECTED_RESPONSE_SIZE: usize = 2012;
58
59 #[test]
61 fn test_compile_form() {
62 let expected_form = TESTDATA_EXPECTED_FORMDATA();
63 let form_data = create_test_form(TESTDATA_FORMDATA_REQUEST).expect("Form");
64
65 assert_eq!(form_data, expected_form, "Form results mismatch!");
66 }
67
68 #[test]
69 fn test_compile_empty_form() {
70 let expected_form = TESTDATA_EXPECTED_FORMDATA_EMPTY();
71 let form_data = create_test_form(TESTDATA_FORMDATA_EMPTY_REQUEST).expect("Form");
72
73 assert_eq!(form_data, expected_form, "Form results mismatch!");
74 }
75
76 #[test]
77 fn test_compile_empty_form_with_boundaries() {
78 let expected_form = TESTDATA_EXPECTED_FORMDATA_EMPTY();
79 let form_data = create_test_form(TESTDATA_FORMDATA_EMPTY_REQUEST_WITH_BOUNDARIES).expect("Form");
80
81 assert_eq!(form_data, expected_form, "Form results mismatch!");
82 }
83
84 #[test]
86 fn test_render_redirect_response() {
87 let url = "http://localhost/redirected";
88 let redirect =
89 rumtk_web_render_redirect!(RUMWebRedirect::Redirect(url.to_string())).unwrap();
90 let redirect_code = redirect.get_code();
91 let redirect_url = redirect.get_url();
92 assert_eq!(redirect_url, url, "Redirect url mismatch!");
93 assert_eq!(redirect_code, 303, "Wrong redirect code!");
94 }
95
96 #[test]
97 fn test_render_redirect_response_temporary() {
98 let url = "http://localhost/redirected";
99 let redirect =
100 rumtk_web_render_redirect!(RUMWebRedirect::RedirectTemporary(url.to_string()))
101 .unwrap();
102 let redirect_code = redirect.get_code();
103 let redirect_url = redirect.get_url();
104 assert_eq!(redirect_url, url, "Redirect url mismatch!");
105 assert_eq!(redirect_code, 307, "Wrong redirect code!");
106 }
107
108 #[test]
109 fn test_render_redirect_response_permanent() {
110 let url = "http://localhost/redirected";
111 let redirect =
112 rumtk_web_render_redirect!(RUMWebRedirect::RedirectPermanent(url.to_string()))
113 .unwrap();
114 let redirect_code = redirect.get_code();
115 let redirect_url = redirect.get_url();
116 assert_eq!(redirect_url, url, "Redirect url mismatch!");
117 assert_eq!(redirect_code, 308, "Wrong redirect code!");
118 }
119
120 #[test]
121 fn test_render_standard_web_component() {
122 let params = rumtk_web_params_map!([(PARAMS_TITLE, "Hello World!")]);
123 let state = SharedAppState::default();
124 let rendered = title(&[], params.get_inner(), state).unwrap().to_string();
125 let rendered_trimmed = rumtk_web_post_process(rendered, RUMWebRedirect::None).unwrap().to_string();
126
127 assert_eq!(
128 rendered_trimmed, TRIMMED_HTML_TITLE_RENDER,
129 "Commponent rendered improperly!"
130 );
131 }
132
133 #[test]
134 fn test_render() {
135 #[derive(RUMWebTemplate)]
136 #[template(source = "<div></div>", ext = "html")]
137 struct Div {}
138
139 let result = rumtk_web_render(Div {}, RUMWebRedirect::None).unwrap();
140 let expected = RUMWebResponse::into_get_response("<div></div>");
141
142 assert_eq!(result, expected, "Test Div template rendered improperly!");
143 }
144
145 #[test]
146 fn test_render_static_component() {
147 let rendered = rumtk_web_render_component!(css);
148 let expected = TRIMMED_HTML_RENDER_CSS;
149
150 assert_eq!(rendered, expected, "Commponent rendered improperly!");
151 }
152
153 #[test]
154 fn test_trim_preformatted_component() {
155 let result = rumtk_web_trim_rendered_html(RAW_HTML_PREFORMATTED.to_string()).unwrap();
156
157 assert_eq!(result, TRIMMED_HTML_PREFORMATTED.to_string(), "Preformatted html string was filtered inappropriately.!");
158 }
159
160 #[test]
162 fn test_job_run() {
163 const HELLO_STR: &str = "Hello World";
164
165 let workers: usize = 5;
166 rumtk_web_init_job_manager!(&workers);
167
168 async fn basic_processor() -> JobResult {
169 let result = RUMString::from(HELLO_STR);
170 let rendered = sanitized(result);
171 Ok(Some(rendered?))
172 }
173
174 let app_state = rumtk_new_lock!(AppState::default());
175 let mut params = RUMWebData::new();
176 let job_id = rumtk_web_get_job_manager!().unwrap().spawn_task(basic_processor()).unwrap();
177 params.insert(RUMString::from(PARAMS_ID), job_id.to_string());
178
179 let result = rumtk_web_get_job_manager!().unwrap().wait_on(&job_id).unwrap().unwrap().unwrap().unwrap();
180
181 rumtk_sleep!(1);
182 let rendered = result.to_string();
183
184 assert_eq!(&rendered, HELLO_STR, "Job returned the wrong result!");
185 }
186
187 #[test]
189 fn test_run_app() {
190 pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
191 let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
192 let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
193 Ok(vec![title])
194 }
195
196 let app_components = rumtk_web_register_app_components!(
197 vec![
198 ("index", index),
199 ]
200 );
201 let app_switches = rumtk_web_register_app_switches!(
202 true,
203 true,
204 true
205 );
206 rumtk_web_run_app!(
207 app_components,
208 app_switches
209 );
210 }
211 #[test]
212 fn test_request_get() {
213 let port = random::<u16>();
214 let port_copy = port.clone();
215 spawn(move || {
216 pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
217 let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
218 let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
219 Ok(vec![title])
220 }
221
222 let app_components = rumtk_web_register_app_components!(
223 vec![
224 ("index", index),
225 ]
226 );
227 let app_switches = rumtk_web_register_app_switches!(
228 false,
229 true,
230 true
231 );
232 rumtk_web_run_app!(
233 app_components,
234 app_switches,
235 Some(port)
236 );
237 });
238 let (code, output) = rumtk_web_sync_get(&rumtk_format!("http://127.0.0.1:{port_copy}/")).unwrap();
239 let output_str = buffer_to_str(&output).unwrap();
240 println!("Output: {}", output_str);
241 assert!(output_str.contains(">Hello World!</h1>"), "Applet responded improperly with wrong response content!");
243 }
244 #[test]
245 fn test_fuzzed_request_get() {
246 let port = random::<u16>();
247 let port_copy = port.clone();
248 spawn(move || {
249 pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
250 let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
251 let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
252 Ok(vec![title])
253 }
254
255 let app_components = rumtk_web_register_app_components!(
256 vec![
257 ("index", index),
258 ]
259 );
260 let app_switches = rumtk_web_register_app_switches!(
261 false,
262 true,
263 true
264 );
265 rumtk_web_run_app!(
266 app_components,
267 app_switches,
268 Some(port)
269 );
270 });
271
272 let fuzz_get_tests = vec![
273 "%Abz"
274 ];
275
276 for fuzz_itm in fuzz_get_tests {
277 let (code, output) = rumtk_web_sync_get(&rumtk_format!("http://127.0.0.1:{port_copy}/{fuzz_itm}")).unwrap();
278 if output.len() != EXPECTED_RESPONSE_SIZE {
279 match code {
280 200 => panic!("Applet responded with wrong response size! => {}", output.len()),
281 _ => {
282 println!("Applet responded with handled error message!");
283 continue;
284 }
285 }
286 }
287 let output_str = buffer_to_str(&output).unwrap();
288 println!("Output: {}", output_str);
289 assert!(output_str.contains(">Hello World!</h1>"), "Applet responded improperly with wrong response content!");
290 }
291 }
292 #[test]
293 fn test_fuzzed_request_get_kills_axum() {
294 let port = random::<u16>();
295 let port_copy = port.clone();
296 spawn(move || {
297 pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
298 let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
299 let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
300 Ok(vec![title])
301 }
302
303 let app_components = rumtk_web_register_app_components!(
304 vec![
305 ("index", index),
306 ]
307 );
308 let app_switches = rumtk_web_register_app_switches!(
309 false,
310 true,
311 true
312 );
313 rumtk_web_run_app!(
314 app_components,
315 app_switches,
316 Some(port)
317 );
318 });
319
320 let fuzz_get_tests = vec![
321 "%Abz"
322 ];
323
324 for fuzz_itm in fuzz_get_tests {
325 let request = rumtk_format!("http://127.0.0.1:{port_copy}/{fuzz_itm}");
326 let (code, output) = rumtk_web_sync_get(&request).unwrap();
327 if output.len() != EXPECTED_RESPONSE_SIZE {
328 match rumtk_web_sync_get(&request) {
329 Ok((c,r)) => {
330 println!("Request[{}] Does not kill axum listener or tokio runtime so allowing... Output: {}", &request,buffer_to_str(&r).unwrap());
331 }
332 Err(e) => {
333 println!("Request[{}] killed axum listener or tokio runtime... Error: {:?}", &request, &e);
334 }
335 }
336 }
337 }
338 }
339
340 #[test]
342 fn test_svg_sanitizer() {
343 let input = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></svg>";
344 let output = sanitize_html(input, false);
345 assert!(output.to_string().contains("<svg><circle"), "SVG and circle tags filtered");
346 }
347 #[test]
348 fn test_svg_sanitizer_full() {
349 let input = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></svg>";
350 let expected: &str = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\"></circle></svg>";
351 let output = sanitize_html(input, false);
352 assert_eq!(&output.to_string(), expected, "Circle tag attributes filtered");
353 }
354
355 #[test]
356 fn test_sanitize_invalid_tag() {
357 let input = "<xml><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></xml>";
358 let output = sanitize_html(input, true);
359 assert!(output.to_string().is_empty(), "XML and circle tags filtered");
360 }
361
362 #[test]
363 fn test_sanitize_script_tag() {
364 let input = r#"<script type="text/javascript">alert('hi');</script>"#;;
365 let output = sanitize_html(input, false);
366 assert!(output.is_empty(), "Script tag was not filtered as expected!");
367 }
368
369 #[test]
370 fn test_sanitize_script_tag_relaxed() {
371 let input = r#"<script type="text/javascript">alert('hi');</script>"#;;
372 let output = sanitize_html(input, true);
373 assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
374 }
375
376 #[test]
377 fn test_sanitize_consecutive_script_tag_relaxed() {
378 let input = r#"<script type="text/javascript">alert('hi');</script><script type="text/javascript">alert('hi2');</script>"#;;
379 let output = sanitize_html(input, true);
380 assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
381 }
382
383 #[test]
384 fn test_sanitize_module_script_tag_relaxed() {
385 let input = r#"<script type="module">alert('hi');</script><script type="text/javascript">alert('hi2');</script>"#;;
386 let output = sanitize_html(input, true);
387 assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
388 }
389
390 #[test]
391 fn test_sanitize_consecutive_module_script_tag_relaxed() {
392 let input = r#"<script type="module">alert('hi');</script><script type="module">alert('hi2');</script>"#;;
393 let output = sanitize_html(input, true);
394 assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
395 }
396}