#![feature(once_cell_get_mut)]
#![feature(macro_metavar_expr)]
#![feature(str_as_str)]
#![feature(random)]
extern crate core;
pub mod api;
pub mod components;
pub mod css;
pub mod pages;
pub mod utils;
pub mod js;
pub use app::*;
pub use utils::*;
#[cfg(test)]
mod tests {
use crate::components::app::css::css;
use crate::components::sanitize::sanitized;
use crate::components::title::title;
use crate::defaults::{PARAMS_ID, PARAMS_TITLE};
use crate::jobs::JobResult;
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};
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};
use crate::{RUMWebResponse, RUMWebTemplate};
use rand::random;
use rumtk_core::buffers::buffer_to_str;
use rumtk_core::strings::{rumtk_format, RUMString};
use rumtk_core::{rumtk_new_lock, rumtk_sleep};
use std::thread::spawn;
const EXPECTED_RESPONSE_SIZE: usize = 2012;
#[test]
fn test_compile_form() {
let expected_form = TESTDATA_EXPECTED_FORMDATA();
let form_data = create_test_form(TESTDATA_FORMDATA_REQUEST).expect("Form");
assert_eq!(form_data, expected_form, "Form results mismatch!");
}
#[test]
fn test_compile_empty_form() {
let expected_form = TESTDATA_EXPECTED_FORMDATA_EMPTY();
let form_data = create_test_form(TESTDATA_FORMDATA_EMPTY_REQUEST).expect("Form");
assert_eq!(form_data, expected_form, "Form results mismatch!");
}
#[test]
fn test_compile_empty_form_with_boundaries() {
let expected_form = TESTDATA_EXPECTED_FORMDATA_EMPTY();
let form_data = create_test_form(TESTDATA_FORMDATA_EMPTY_REQUEST_WITH_BOUNDARIES).expect("Form");
assert_eq!(form_data, expected_form, "Form results mismatch!");
}
#[test]
fn test_render_redirect_response() {
let url = "http://localhost/redirected";
let redirect =
rumtk_web_render_redirect!(RUMWebRedirect::Redirect(url.to_string())).unwrap();
let redirect_code = redirect.get_code();
let redirect_url = redirect.get_url();
assert_eq!(redirect_url, url, "Redirect url mismatch!");
assert_eq!(redirect_code, 303, "Wrong redirect code!");
}
#[test]
fn test_render_redirect_response_temporary() {
let url = "http://localhost/redirected";
let redirect =
rumtk_web_render_redirect!(RUMWebRedirect::RedirectTemporary(url.to_string()))
.unwrap();
let redirect_code = redirect.get_code();
let redirect_url = redirect.get_url();
assert_eq!(redirect_url, url, "Redirect url mismatch!");
assert_eq!(redirect_code, 307, "Wrong redirect code!");
}
#[test]
fn test_render_redirect_response_permanent() {
let url = "http://localhost/redirected";
let redirect =
rumtk_web_render_redirect!(RUMWebRedirect::RedirectPermanent(url.to_string()))
.unwrap();
let redirect_code = redirect.get_code();
let redirect_url = redirect.get_url();
assert_eq!(redirect_url, url, "Redirect url mismatch!");
assert_eq!(redirect_code, 308, "Wrong redirect code!");
}
#[test]
fn test_render_standard_web_component() {
let params = rumtk_web_params_map!([(PARAMS_TITLE, "Hello World!")]);
let state = SharedAppState::default();
let rendered = title(&[], params.get_inner(), state).unwrap().to_string();
let rendered_trimmed = rumtk_web_post_process(rendered, RUMWebRedirect::None).unwrap().to_string();
assert_eq!(
rendered_trimmed, TRIMMED_HTML_TITLE_RENDER,
"Commponent rendered improperly!"
);
}
#[test]
fn test_render() {
#[derive(RUMWebTemplate)]
#[template(source = "<div></div>", ext = "html")]
struct Div {}
let result = rumtk_web_render(Div {}, RUMWebRedirect::None).unwrap();
let expected = RUMWebResponse::into_get_response("<div></div>");
assert_eq!(result, expected, "Test Div template rendered improperly!");
}
#[test]
fn test_render_static_component() {
let rendered = rumtk_web_render_component!(css);
let expected = TRIMMED_HTML_RENDER_CSS;
assert_eq!(rendered, expected, "Commponent rendered improperly!");
}
#[test]
fn test_trim_preformatted_component() {
let result = rumtk_web_trim_rendered_html(RAW_HTML_PREFORMATTED.to_string()).unwrap();
assert_eq!(result, TRIMMED_HTML_PREFORMATTED.to_string(), "Preformatted html string was filtered inappropriately.!");
}
#[test]
fn test_job_run() {
const HELLO_STR: &str = "Hello World";
let workers: usize = 5;
rumtk_web_init_job_manager!(&workers);
async fn basic_processor() -> JobResult {
let result = RUMString::from(HELLO_STR);
let rendered = sanitized(result);
Ok(Some(rendered?))
}
let app_state = rumtk_new_lock!(AppState::default());
let mut params = RUMWebData::new();
let job_id = rumtk_web_get_job_manager!().unwrap().spawn_task(basic_processor()).unwrap();
params.insert(RUMString::from(PARAMS_ID), job_id.to_string());
let result = rumtk_web_get_job_manager!().unwrap().wait_on(&job_id).unwrap().unwrap().unwrap().unwrap();
rumtk_sleep!(1);
let rendered = result.to_string();
assert_eq!(&rendered, HELLO_STR, "Job returned the wrong result!");
}
#[test]
fn test_run_app() {
pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
Ok(vec![title])
}
let app_components = rumtk_web_register_app_components!(
vec![
("index", index),
]
);
let app_switches = rumtk_web_register_app_switches!(
true,
true,
true
);
rumtk_web_run_app!(
app_components,
app_switches
);
}
#[test]
fn test_request_get() {
let port = random::<u16>();
let port_copy = port.clone();
spawn(move || {
pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
Ok(vec![title])
}
let app_components = rumtk_web_register_app_components!(
vec![
("index", index),
]
);
let app_switches = rumtk_web_register_app_switches!(
false,
true,
true
);
rumtk_web_run_app!(
app_components,
app_switches,
Some(port)
);
});
let (code, output) = rumtk_web_sync_get(&rumtk_format!("http://127.0.0.1:{port_copy}/")).unwrap();
let output_str = buffer_to_str(&output).unwrap();
println!("Output: {}", output_str);
assert!(output_str.contains(">Hello World!</h1>"), "Applet responded improperly with wrong response content!");
}
#[test]
fn test_fuzzed_request_get() {
let port = random::<u16>();
let port_copy = port.clone();
spawn(move || {
pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
Ok(vec![title])
}
let app_components = rumtk_web_register_app_components!(
vec![
("index", index),
]
);
let app_switches = rumtk_web_register_app_switches!(
false,
true,
true
);
rumtk_web_run_app!(
app_components,
app_switches,
Some(port)
);
});
let fuzz_get_tests = vec![
"%Abz"
];
for fuzz_itm in fuzz_get_tests {
let (code, output) = rumtk_web_sync_get(&rumtk_format!("http://127.0.0.1:{port_copy}/{fuzz_itm}")).unwrap();
if output.len() != EXPECTED_RESPONSE_SIZE {
match code {
200 => panic!("Applet responded with wrong response size! => {}", output.len()),
_ => {
println!("Applet responded with handled error message!");
continue;
}
}
}
let output_str = buffer_to_str(&output).unwrap();
println!("Output: {}", output_str);
assert!(output_str.contains(">Hello World!</h1>"), "Applet responded improperly with wrong response content!");
}
}
#[test]
fn test_fuzzed_request_get_kills_axum() {
let port = random::<u16>();
let port_copy = port.clone();
spawn(move || {
pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
let title_params = rumtk_web_params_map!([("title", "Hello World!")]);
let title = title(&[], title_params.get_inner(), app_state.clone())?.to_string();
Ok(vec![title])
}
let app_components = rumtk_web_register_app_components!(
vec![
("index", index),
]
);
let app_switches = rumtk_web_register_app_switches!(
false,
true,
true
);
rumtk_web_run_app!(
app_components,
app_switches,
Some(port)
);
});
let fuzz_get_tests = vec![
"%Abz"
];
for fuzz_itm in fuzz_get_tests {
let request = rumtk_format!("http://127.0.0.1:{port_copy}/{fuzz_itm}");
let (code, output) = rumtk_web_sync_get(&request).unwrap();
if output.len() != EXPECTED_RESPONSE_SIZE {
match rumtk_web_sync_get(&request) {
Ok((c,r)) => {
println!("Request[{}] Does not kill axum listener or tokio runtime so allowing... Output: {}", &request,buffer_to_str(&r).unwrap());
}
Err(e) => {
println!("Request[{}] killed axum listener or tokio runtime... Error: {:?}", &request, &e);
}
}
}
}
}
#[test]
fn test_svg_sanitizer() {
let input = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></svg>";
let output = sanitize_html(input, false);
assert!(output.to_string().contains("<svg><circle"), "SVG and circle tags filtered");
}
#[test]
fn test_svg_sanitizer_full() {
let input = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></svg>";
let expected: &str = "<svg><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\"></circle></svg>";
let output = sanitize_html(input, false);
assert_eq!(&output.to_string(), expected, "Circle tag attributes filtered");
}
#[test]
fn test_sanitize_invalid_tag() {
let input = "<xml><circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"red\" /></xml>";
let output = sanitize_html(input, true);
assert!(output.to_string().is_empty(), "XML and circle tags filtered");
}
#[test]
fn test_sanitize_script_tag() {
let input = r#"<script type="text/javascript">alert('hi');</script>"#;;
let output = sanitize_html(input, false);
assert!(output.is_empty(), "Script tag was not filtered as expected!");
}
#[test]
fn test_sanitize_script_tag_relaxed() {
let input = r#"<script type="text/javascript">alert('hi');</script>"#;;
let output = sanitize_html(input, true);
assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
}
#[test]
fn test_sanitize_consecutive_script_tag_relaxed() {
let input = r#"<script type="text/javascript">alert('hi');</script><script type="text/javascript">alert('hi2');</script>"#;;
let output = sanitize_html(input, true);
assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
}
#[test]
fn test_sanitize_module_script_tag_relaxed() {
let input = r#"<script type="module">alert('hi');</script><script type="text/javascript">alert('hi2');</script>"#;;
let output = sanitize_html(input, true);
assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
}
#[test]
fn test_sanitize_consecutive_module_script_tag_relaxed() {
let input = r#"<script type="module">alert('hi');</script><script type="module">alert('hi2');</script>"#;;
let output = sanitize_html(input, true);
assert_eq!(input, &output, "Script tag was filtered when it shouldn't have or attributes were stripped!");
}
}