commit
4f2944a600
|
@ -2,8 +2,15 @@ use assert_cmd::prelude::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn print_version() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_print_version() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd.arg("-V").output().unwrap();
|
let out = cmd.arg("-V").output().unwrap();
|
||||||
|
|
||||||
|
@ -23,7 +30,7 @@ fn print_version() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_input_empty_target() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_bad_input_empty_target() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd.arg("").output().unwrap();
|
let out = cmd.arg("").output().unwrap();
|
||||||
|
|
||||||
|
@ -43,7 +50,7 @@ fn bad_input_empty_target() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bad_input_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_bad_input_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap();
|
let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap();
|
||||||
|
|
||||||
|
@ -63,7 +70,7 @@ fn bad_input_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn isolate_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_isolate_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("-I")
|
.arg("-I")
|
||||||
|
@ -89,7 +96,7 @@ fn isolate_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remove_css_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_remove_css_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
|
@ -116,7 +123,7 @@ fn remove_css_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remove_frames_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_remove_frames_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("-f")
|
.arg("-f")
|
||||||
|
@ -142,7 +149,7 @@ fn remove_frames_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remove_images_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_remove_images_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("-i")
|
.arg("-i")
|
||||||
|
@ -174,7 +181,7 @@ Hi\
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remove_js_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_remove_js_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("-j")
|
.arg("-j")
|
||||||
|
@ -203,7 +210,7 @@ fn remove_js_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let cwd_normalized: String =
|
let cwd_normalized: String =
|
||||||
str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
|
str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
|
||||||
|
@ -251,7 +258,8 @@ fn local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::error::Error>>
|
||||||
|
{
|
||||||
let cwd = env::current_dir().unwrap();
|
let cwd = env::current_dir().unwrap();
|
||||||
let cwd_normalized: String =
|
let cwd_normalized: String =
|
||||||
str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
|
str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
|
||||||
|
@ -290,7 +298,6 @@ fn local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::err
|
||||||
);
|
);
|
||||||
|
|
||||||
// STDERR should contain only the target file
|
// STDERR should contain only the target file
|
||||||
let cwd = env::current_dir().unwrap();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
std::str::from_utf8(&out.stderr).unwrap(),
|
std::str::from_utf8(&out.stderr).unwrap(),
|
||||||
format!(
|
format!(
|
||||||
|
@ -307,7 +314,7 @@ fn local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::err
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn local_file_url_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
fn passing_local_file_url_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let cwd = env::current_dir().unwrap();
|
let cwd = env::current_dir().unwrap();
|
||||||
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" };
|
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" };
|
||||||
|
@ -370,8 +377,8 @@ fn local_file_url_target_input() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn security_disallow_local_assets_within_data_url_targets() -> Result<(), Box<dyn std::error::Error>>
|
fn passing_security_disallow_local_assets_within_data_url_targets(
|
||||||
{
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
|
||||||
let out = cmd
|
let out = cmd
|
||||||
.arg("data:text/html,%3Cscript%20src=\"src/tests/data/local-script.js\"%3E%3C/script%3E")
|
.arg("data:text/html,%3Cscript%20src=\"src/tests/data/local-script.js\"%3E%3C/script%3E")
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
use crate::html;
|
||||||
|
use html5ever::rcdom::{Handle, NodeData};
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_node_name() {
|
||||||
|
let html = "<!doctype html><html><HEAD></HEAD><body><div><P></P></div></body></html>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
fn test_walk(node: &Handle, i: &mut i8) {
|
||||||
|
*i += 1;
|
||||||
|
|
||||||
|
match &node.data {
|
||||||
|
NodeData::Document => {
|
||||||
|
for child in node.children.borrow().iter() {
|
||||||
|
test_walk(child, &mut *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeData::Element { ref name, .. } => {
|
||||||
|
let node_name = name.local.as_ref().to_string();
|
||||||
|
let parent = html::get_parent_node(node);
|
||||||
|
let parent_node_name = html::get_node_name(&parent);
|
||||||
|
if node_name == "head" || node_name == "body" {
|
||||||
|
assert_eq!(parent_node_name, "html");
|
||||||
|
} else if node_name == "div" {
|
||||||
|
assert_eq!(parent_node_name, "body");
|
||||||
|
} else if node_name == "p" {
|
||||||
|
assert_eq!(parent_node_name, "div");
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in node.children.borrow().iter() {
|
||||||
|
test_walk(child, &mut *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test_walk(&dom.document, &mut count);
|
||||||
|
|
||||||
|
assert_eq!(count, 7);
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::html;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_icon() {
|
||||||
|
assert!(html::is_icon("icon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_shortcut_icon_capitalized() {
|
||||||
|
assert!(html::is_icon("Shortcut Icon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_icon_uppercase() {
|
||||||
|
assert!(html::is_icon("ICON"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_mask_icon() {
|
||||||
|
assert!(html::is_icon("mask-icon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_fluid_icon() {
|
||||||
|
assert!(html::is_icon("fluid-icon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_stylesheet() {
|
||||||
|
assert!(!html::is_icon("stylesheet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_empty_string() {
|
||||||
|
assert!(!html::is_icon(""));
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
mod get_node_name;
|
||||||
|
mod is_icon;
|
||||||
|
mod stringify_document;
|
||||||
|
mod walk_and_embed_assets;
|
|
@ -0,0 +1,188 @@
|
||||||
|
use crate::html;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_div_as_root_element() {
|
||||||
|
let html = "<div><script src=\"some.js\"></script></div>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
|
||||||
|
let opt_no_css: bool = false;
|
||||||
|
let opt_no_frames: bool = false;
|
||||||
|
let opt_no_js: bool = false;
|
||||||
|
let opt_no_images: bool = false;
|
||||||
|
let opt_isolate: bool = false;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html::stringify_document(
|
||||||
|
&dom.document,
|
||||||
|
opt_no_css,
|
||||||
|
opt_no_frames,
|
||||||
|
opt_no_js,
|
||||||
|
opt_no_images,
|
||||||
|
opt_isolate,
|
||||||
|
),
|
||||||
|
"<html><head></head><body><div><script src=\"some.js\"></script></div></body></html>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_full_page_with_no_html_head_or_body() {
|
||||||
|
let html = "<title>Isolated document</title>\
|
||||||
|
<link rel=\"something\" href=\"some.css\" />\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
||||||
|
<div><script src=\"some.js\"></script></div>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
|
||||||
|
let opt_no_css: bool = false;
|
||||||
|
let opt_no_frames: bool = false;
|
||||||
|
let opt_no_js: bool = false;
|
||||||
|
let opt_no_images: bool = false;
|
||||||
|
let opt_isolate: bool = true;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html::stringify_document(
|
||||||
|
&dom.document,
|
||||||
|
opt_no_css,
|
||||||
|
opt_no_frames,
|
||||||
|
opt_no_js,
|
||||||
|
opt_no_images,
|
||||||
|
opt_isolate,
|
||||||
|
),
|
||||||
|
"<html>\
|
||||||
|
<head>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\
|
||||||
|
<title>Isolated document</title>\
|
||||||
|
<link rel=\"something\" href=\"some.css\">\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
||||||
|
</head>\
|
||||||
|
<body>\
|
||||||
|
<div>\
|
||||||
|
<script src=\"some.js\"></script>\
|
||||||
|
</div>\
|
||||||
|
</body>\
|
||||||
|
</html>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_doctype_and_the_rest_no_html_head_or_body() {
|
||||||
|
let html = "<!doctype html>\
|
||||||
|
<title>Unstyled document</title>\
|
||||||
|
<link rel=\"stylesheet\" href=\"main.css\"/>\
|
||||||
|
<div style=\"display: none;\"></div>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
|
||||||
|
let opt_no_css: bool = true;
|
||||||
|
let opt_no_frames: bool = false;
|
||||||
|
let opt_no_js: bool = false;
|
||||||
|
let opt_no_images: bool = false;
|
||||||
|
let opt_isolate: bool = false;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html::stringify_document(
|
||||||
|
&dom.document,
|
||||||
|
opt_no_css,
|
||||||
|
opt_no_frames,
|
||||||
|
opt_no_js,
|
||||||
|
opt_no_images,
|
||||||
|
opt_isolate,
|
||||||
|
),
|
||||||
|
"<!DOCTYPE html>\
|
||||||
|
<html>\
|
||||||
|
<head>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
|
||||||
|
<title>Unstyled document</title>\
|
||||||
|
<link rel=\"stylesheet\" href=\"main.css\">\
|
||||||
|
</head>\
|
||||||
|
<body><div style=\"display: none;\"></div></body>\
|
||||||
|
</html>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_doctype_and_the_rest_no_html_head_or_body_forbid_frames() {
|
||||||
|
let html = "<!doctype html>\
|
||||||
|
<title>Frameless document</title>\
|
||||||
|
<link rel=\"something\"/>\
|
||||||
|
<div><script src=\"some.js\"></script></div>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
|
||||||
|
let opt_no_css: bool = false;
|
||||||
|
let opt_no_frames: bool = true;
|
||||||
|
let opt_no_js: bool = false;
|
||||||
|
let opt_no_images: bool = false;
|
||||||
|
let opt_isolate: bool = false;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html::stringify_document(
|
||||||
|
&dom.document,
|
||||||
|
opt_no_css,
|
||||||
|
opt_no_frames,
|
||||||
|
opt_no_js,
|
||||||
|
opt_no_images,
|
||||||
|
opt_isolate,
|
||||||
|
),
|
||||||
|
"<!DOCTYPE html>\
|
||||||
|
<html>\
|
||||||
|
<head>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\
|
||||||
|
<title>Frameless document</title>\
|
||||||
|
<link rel=\"something\">\
|
||||||
|
</head>\
|
||||||
|
<body><div><script src=\"some.js\"></script></div></body>\
|
||||||
|
</html>"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_doctype_and_the_rest_all_forbidden() {
|
||||||
|
let html = "<!doctype html>\
|
||||||
|
<title>no-frame no-css no-js no-image isolated document</title>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
||||||
|
<link rel=\"stylesheet\" href=\"some.css\">\
|
||||||
|
<div>\
|
||||||
|
<script src=\"some.js\"></script>\
|
||||||
|
<img style=\"width: 100%;\" src=\"some.png\" />\
|
||||||
|
<iframe src=\"some.html\"></iframe>\
|
||||||
|
</div>";
|
||||||
|
let dom = html::html_to_dom(&html);
|
||||||
|
|
||||||
|
let opt_isolate: bool = true;
|
||||||
|
let opt_no_css: bool = true;
|
||||||
|
let opt_no_frames: bool = true;
|
||||||
|
let opt_no_js: bool = true;
|
||||||
|
let opt_no_images: bool = true;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
html::stringify_document(
|
||||||
|
&dom.document,
|
||||||
|
opt_no_css,
|
||||||
|
opt_no_frames,
|
||||||
|
opt_no_js,
|
||||||
|
opt_no_images,
|
||||||
|
opt_isolate,
|
||||||
|
),
|
||||||
|
"<!DOCTYPE html>\
|
||||||
|
<html>\
|
||||||
|
<head>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; frame-src 'none';child-src 'none'; script-src 'none'; img-src data:;\"></meta>\
|
||||||
|
<title>no-frame no-css no-js no-image isolated document</title>\
|
||||||
|
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
||||||
|
<link rel=\"stylesheet\" href=\"some.css\">\
|
||||||
|
</head>\
|
||||||
|
<body>\
|
||||||
|
<div>\
|
||||||
|
<script src=\"some.js\"></script>\
|
||||||
|
<img style=\"width: 100%;\" src=\"some.png\">\
|
||||||
|
<iframe src=\"some.html\"></iframe>\
|
||||||
|
</div>\
|
||||||
|
</body>\
|
||||||
|
</html>"
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,70 +1,21 @@
|
||||||
use crate::html::{
|
use crate::html;
|
||||||
get_node_name, get_parent_node, html_to_dom, is_icon, stringify_document, walk_and_embed_assets,
|
|
||||||
};
|
|
||||||
use html5ever::rcdom::{Handle, NodeData};
|
|
||||||
use html5ever::serialize::{serialize, SerializeOpts};
|
use html5ever::serialize::{serialize, SerializeOpts};
|
||||||
use reqwest::blocking::Client;
|
use reqwest::blocking::Client;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
fn test_is_icon() {
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
assert_eq!(is_icon("icon"), true);
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
assert_eq!(is_icon("Shortcut Icon"), true);
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
assert_eq!(is_icon("ICON"), true);
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
assert_eq!(is_icon("mask-icon"), true);
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
assert_eq!(is_icon("fluid-icon"), true);
|
|
||||||
assert_eq!(is_icon("stylesheet"), false);
|
|
||||||
assert_eq!(is_icon(""), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_parent_node_name() {
|
fn passing_basic() {
|
||||||
let html = "<!doctype html><html><HEAD></HEAD><body><div><P></P></div></body></html>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
fn test_walk(node: &Handle, i: &mut i8) {
|
|
||||||
*i += 1;
|
|
||||||
|
|
||||||
match &node.data {
|
|
||||||
NodeData::Document => {
|
|
||||||
for child in node.children.borrow().iter() {
|
|
||||||
test_walk(child, &mut *i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NodeData::Element { ref name, .. } => {
|
|
||||||
let node_name = name.local.as_ref().to_string();
|
|
||||||
let parent = get_parent_node(node);
|
|
||||||
let parent_node_name = get_node_name(&parent);
|
|
||||||
if node_name == "head" || node_name == "body" {
|
|
||||||
assert_eq!(parent_node_name, "html");
|
|
||||||
} else if node_name == "div" {
|
|
||||||
assert_eq!(parent_node_name, "body");
|
|
||||||
} else if node_name == "p" {
|
|
||||||
assert_eq!(parent_node_name, "div");
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{}", node_name);
|
|
||||||
|
|
||||||
for child in node.children.borrow().iter() {
|
|
||||||
test_walk(child, &mut *i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
test_walk(&dom.document, &mut count);
|
|
||||||
|
|
||||||
assert_eq!(count, 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_walk_and_embed_assets() {
|
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
let html = "<div><P></P></div>";
|
let html = "<div><P></P></div>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
|
|
||||||
let opt_no_css: bool = false;
|
let opt_no_css: bool = false;
|
||||||
|
@ -75,7 +26,7 @@ fn test_walk_and_embed_assets() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -97,9 +48,9 @@ fn test_walk_and_embed_assets() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_ensure_no_recursive_iframe() {
|
fn passing_ensure_no_recursive_iframe() {
|
||||||
let html = "<div><P></P><iframe src=\"\"></iframe></div>";
|
let html = "<div><P></P><iframe src=\"\"></iframe></div>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -111,7 +62,7 @@ fn test_walk_and_embed_assets_ensure_no_recursive_iframe() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -133,9 +84,9 @@ fn test_walk_and_embed_assets_ensure_no_recursive_iframe() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_ensure_no_recursive_frame() {
|
fn passing_ensure_no_recursive_frame() {
|
||||||
let html = "<frameset><frame src=\"\"></frameset>";
|
let html = "<frameset><frame src=\"\"></frameset>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -147,7 +98,7 @@ fn test_walk_and_embed_assets_ensure_no_recursive_frame() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -169,11 +120,11 @@ fn test_walk_and_embed_assets_ensure_no_recursive_frame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_no_css() {
|
fn passing_no_css() {
|
||||||
let html = "<link rel=\"stylesheet\" href=\"main.css\">\
|
let html = "<link rel=\"stylesheet\" href=\"main.css\">\
|
||||||
<style>html{background-color: #000;}</style>\
|
<style>html{background-color: #000;}</style>\
|
||||||
<div style=\"display: none;\"></div>";
|
<div style=\"display: none;\"></div>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -184,7 +135,7 @@ fn test_walk_and_embed_assets_no_css() {
|
||||||
let opt_silent = true;
|
let opt_silent = true;
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -214,10 +165,10 @@ fn test_walk_and_embed_assets_no_css() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_no_images() {
|
fn passing_no_images() {
|
||||||
let html = "<link rel=\"icon\" href=\"favicon.ico\">\
|
let html = "<link rel=\"icon\" href=\"favicon.ico\">\
|
||||||
<div><img src=\"http://localhost/assets/mono_lisa.png\" /></div>";
|
<div><img src=\"http://localhost/assets/mono_lisa.png\" /></div>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -229,7 +180,7 @@ fn test_walk_and_embed_assets_no_images() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -262,9 +213,9 @@ fn test_walk_and_embed_assets_no_images() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn walk_and_embed_assets_no_body_background_images() {
|
fn passing_no_body_background_images() {
|
||||||
let html = "<body background=\"no/such/image.png\" background=\"no/such/image2.png\"></body>";
|
let html = "<body background=\"no/such/image.png\" background=\"no/such/image2.png\"></body>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -276,7 +227,7 @@ fn walk_and_embed_assets_no_body_background_images() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -298,9 +249,9 @@ fn walk_and_embed_assets_no_body_background_images() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_no_frames() {
|
fn passing_no_frames() {
|
||||||
let html = "<frameset><frame src=\"http://trackbook.com\"></frameset>";
|
let html = "<frameset><frame src=\"http://trackbook.com\"></frameset>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -311,7 +262,7 @@ fn test_walk_and_embed_assets_no_frames() {
|
||||||
let opt_silent = true;
|
let opt_silent = true;
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -333,9 +284,9 @@ fn test_walk_and_embed_assets_no_frames() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_no_iframes() {
|
fn passing_no_iframes() {
|
||||||
let html = "<iframe src=\"http://trackbook.com\"></iframe>";
|
let html = "<iframe src=\"http://trackbook.com\"></iframe>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -346,7 +297,7 @@ fn test_walk_and_embed_assets_no_iframes() {
|
||||||
let opt_silent = true;
|
let opt_silent = true;
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -368,12 +319,12 @@ fn test_walk_and_embed_assets_no_iframes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_assets_no_js() {
|
fn passing_no_js() {
|
||||||
let html = "<div onClick=\"void(0)\">\
|
let html = "<div onClick=\"void(0)\">\
|
||||||
<script src=\"http://localhost/assets/some.js\"></script>\
|
<script src=\"http://localhost/assets/some.js\"></script>\
|
||||||
<script>alert(1)</script>\
|
<script>alert(1)</script>\
|
||||||
</div>";
|
</div>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
|
|
||||||
|
@ -385,7 +336,7 @@ fn test_walk_and_embed_assets_no_js() {
|
||||||
|
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -408,11 +359,11 @@ fn test_walk_and_embed_assets_no_js() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_walk_and_embed_with_no_integrity() {
|
fn passing_with_no_integrity() {
|
||||||
let html = "<title>No integrity</title>\
|
let html = "<title>No integrity</title>\
|
||||||
<link integrity=\"sha384-...\" rel=\"something\"/>\
|
<link integrity=\"sha384-...\" rel=\"something\"/>\
|
||||||
<script integrity=\"sha384-...\" src=\"some.js\"></script>";
|
<script integrity=\"sha384-...\" src=\"some.js\"></script>";
|
||||||
let dom = html_to_dom(&html);
|
let dom = html::html_to_dom(&html);
|
||||||
let url = "http://localhost";
|
let url = "http://localhost";
|
||||||
let cache = &mut HashMap::new();
|
let cache = &mut HashMap::new();
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
@ -422,7 +373,7 @@ fn test_walk_and_embed_with_no_integrity() {
|
||||||
let opt_no_images: bool = true;
|
let opt_no_images: bool = true;
|
||||||
let opt_silent = true;
|
let opt_silent = true;
|
||||||
|
|
||||||
walk_and_embed_assets(
|
html::walk_and_embed_assets(
|
||||||
cache,
|
cache,
|
||||||
&client,
|
&client,
|
||||||
&url,
|
&url,
|
||||||
|
@ -445,183 +396,3 @@ fn test_walk_and_embed_with_no_integrity() {
|
||||||
</html>"
|
</html>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stringify_document() {
|
|
||||||
let html = "<div><script src=\"some.js\"></script></div>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
|
|
||||||
let opt_no_css: bool = false;
|
|
||||||
let opt_no_frames: bool = false;
|
|
||||||
let opt_no_js: bool = false;
|
|
||||||
let opt_no_images: bool = false;
|
|
||||||
let opt_isolate: bool = false;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stringify_document(
|
|
||||||
&dom.document,
|
|
||||||
opt_no_css,
|
|
||||||
opt_no_frames,
|
|
||||||
opt_no_js,
|
|
||||||
opt_no_images,
|
|
||||||
opt_isolate,
|
|
||||||
),
|
|
||||||
"<html><head></head><body><div><script src=\"some.js\"></script></div></body></html>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stringify_document_isolate() {
|
|
||||||
let html = "<title>Isolated document</title>\
|
|
||||||
<link rel=\"something\" href=\"some.css\" />\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
|
||||||
<div><script src=\"some.js\"></script></div>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
|
|
||||||
let opt_no_css: bool = false;
|
|
||||||
let opt_no_frames: bool = false;
|
|
||||||
let opt_no_js: bool = false;
|
|
||||||
let opt_no_images: bool = false;
|
|
||||||
let opt_isolate: bool = true;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stringify_document(
|
|
||||||
&dom.document,
|
|
||||||
opt_no_css,
|
|
||||||
opt_no_frames,
|
|
||||||
opt_no_js,
|
|
||||||
opt_no_images,
|
|
||||||
opt_isolate,
|
|
||||||
),
|
|
||||||
"<html>\
|
|
||||||
<head>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\
|
|
||||||
<title>Isolated document</title>\
|
|
||||||
<link rel=\"something\" href=\"some.css\">\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
|
||||||
</head>\
|
|
||||||
<body>\
|
|
||||||
<div>\
|
|
||||||
<script src=\"some.js\"></script>\
|
|
||||||
</div>\
|
|
||||||
</body>\
|
|
||||||
</html>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stringify_document_no_css() {
|
|
||||||
let html = "<!doctype html>\
|
|
||||||
<title>Unstyled document</title>\
|
|
||||||
<link rel=\"stylesheet\" href=\"main.css\"/>\
|
|
||||||
<div style=\"display: none;\"></div>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
|
|
||||||
let opt_no_css: bool = true;
|
|
||||||
let opt_no_frames: bool = false;
|
|
||||||
let opt_no_js: bool = false;
|
|
||||||
let opt_no_images: bool = false;
|
|
||||||
let opt_isolate: bool = false;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stringify_document(
|
|
||||||
&dom.document,
|
|
||||||
opt_no_css,
|
|
||||||
opt_no_frames,
|
|
||||||
opt_no_js,
|
|
||||||
opt_no_images,
|
|
||||||
opt_isolate,
|
|
||||||
),
|
|
||||||
"<!DOCTYPE html>\
|
|
||||||
<html>\
|
|
||||||
<head>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
|
|
||||||
<title>Unstyled document</title>\
|
|
||||||
<link rel=\"stylesheet\" href=\"main.css\">\
|
|
||||||
</head>\
|
|
||||||
<body><div style=\"display: none;\"></div></body>\
|
|
||||||
</html>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stringify_document_no_frames() {
|
|
||||||
let html = "<!doctype html>\
|
|
||||||
<title>Frameless document</title>\
|
|
||||||
<link rel=\"something\"/>\
|
|
||||||
<div><script src=\"some.js\"></script></div>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
|
|
||||||
let opt_no_css: bool = false;
|
|
||||||
let opt_no_frames: bool = true;
|
|
||||||
let opt_no_js: bool = false;
|
|
||||||
let opt_no_images: bool = false;
|
|
||||||
let opt_isolate: bool = false;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stringify_document(
|
|
||||||
&dom.document,
|
|
||||||
opt_no_css,
|
|
||||||
opt_no_frames,
|
|
||||||
opt_no_js,
|
|
||||||
opt_no_images,
|
|
||||||
opt_isolate,
|
|
||||||
),
|
|
||||||
"<!DOCTYPE html>\
|
|
||||||
<html>\
|
|
||||||
<head>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\
|
|
||||||
<title>Frameless document</title>\
|
|
||||||
<link rel=\"something\">\
|
|
||||||
</head>\
|
|
||||||
<body><div><script src=\"some.js\"></script></div></body>\
|
|
||||||
</html>"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stringify_document_isolate_no_frames_no_js_no_css_no_images() {
|
|
||||||
let html = "<!doctype html>\
|
|
||||||
<title>no-frame no-css no-js no-image isolated document</title>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
|
||||||
<link rel=\"stylesheet\" href=\"some.css\">\
|
|
||||||
<div>\
|
|
||||||
<script src=\"some.js\"></script>\
|
|
||||||
<img style=\"width: 100%;\" src=\"some.png\" />\
|
|
||||||
<iframe src=\"some.html\"></iframe>\
|
|
||||||
</div>";
|
|
||||||
let dom = html_to_dom(&html);
|
|
||||||
|
|
||||||
let opt_isolate: bool = true;
|
|
||||||
let opt_no_css: bool = true;
|
|
||||||
let opt_no_frames: bool = true;
|
|
||||||
let opt_no_js: bool = true;
|
|
||||||
let opt_no_images: bool = true;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
stringify_document(
|
|
||||||
&dom.document,
|
|
||||||
opt_no_css,
|
|
||||||
opt_no_frames,
|
|
||||||
opt_no_js,
|
|
||||||
opt_no_images,
|
|
||||||
opt_isolate,
|
|
||||||
),
|
|
||||||
"<!DOCTYPE html>\
|
|
||||||
<html>\
|
|
||||||
<head>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; frame-src 'none';child-src 'none'; script-src 'none'; img-src data:;\"></meta>\
|
|
||||||
<title>no-frame no-css no-js no-image isolated document</title>\
|
|
||||||
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
|
|
||||||
<link rel=\"stylesheet\" href=\"some.css\">\
|
|
||||||
</head>\
|
|
||||||
<body>\
|
|
||||||
<div>\
|
|
||||||
<script src=\"some.js\"></script>\
|
|
||||||
<img style=\"width: 100%;\" src=\"some.png\">\
|
|
||||||
<iframe src=\"some.html\"></iframe>\
|
|
||||||
</div>\
|
|
||||||
</body>\
|
|
||||||
</html>"
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
use crate::js::attr_is_event_handler;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_attr_is_event_handler() {
|
|
||||||
// passing
|
|
||||||
assert!(attr_is_event_handler("onBlur"));
|
|
||||||
assert!(attr_is_event_handler("onclick"));
|
|
||||||
assert!(attr_is_event_handler("onClick"));
|
|
||||||
// failing
|
|
||||||
assert!(!attr_is_event_handler("href"));
|
|
||||||
assert!(!attr_is_event_handler(""));
|
|
||||||
assert!(!attr_is_event_handler("class"));
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
use crate::js;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_onblur_camelcase() {
|
||||||
|
assert!(js::attr_is_event_handler("onBlur"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_onclick_lowercase() {
|
||||||
|
assert!(js::attr_is_event_handler("onclick"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_onclick_camelcase() {
|
||||||
|
assert!(js::attr_is_event_handler("onClick"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_href() {
|
||||||
|
assert!(!js::attr_is_event_handler("href"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_empty_string() {
|
||||||
|
assert!(!js::attr_is_event_handler(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_class() {
|
||||||
|
assert!(!js::attr_is_event_handler("class"));
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
mod attr_is_event_handler;
|
|
@ -1,383 +0,0 @@
|
||||||
use crate::utils;
|
|
||||||
use reqwest::blocking::Client;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::env;
|
|
||||||
use url::ParseError;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn data_to_data_url() {
|
|
||||||
let mime = "application/javascript";
|
|
||||||
let data = "var word = 'hello';\nalert(word);\n";
|
|
||||||
let datauri = utils::data_to_data_url(mime, data.as_bytes());
|
|
||||||
assert_eq!(
|
|
||||||
&datauri,
|
|
||||||
"data:application/javascript;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn detect_mimetype() {
|
|
||||||
// Image
|
|
||||||
assert_eq!(utils::detect_mimetype(b"GIF87a"), "image/gif");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"GIF89a"), "image/gif");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\xFF\xD8\xFF"), "image/jpeg");
|
|
||||||
assert_eq!(
|
|
||||||
utils::detect_mimetype(b"\x89PNG\x0D\x0A\x1A\x0A"),
|
|
||||||
"image/png"
|
|
||||||
);
|
|
||||||
assert_eq!(utils::detect_mimetype(b"<?xml "), "image/svg+xml");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"<svg "), "image/svg+xml");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"RIFF....WEBPVP8 "), "image/webp");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\x00\x00\x01\x00"), "image/x-icon");
|
|
||||||
|
|
||||||
// Audio
|
|
||||||
assert_eq!(utils::detect_mimetype(b"ID3"), "audio/mpeg");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\xFF\x0E"), "audio/mpeg");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\xFF\x0F"), "audio/mpeg");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"OggS"), "audio/ogg");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"RIFF....WAVEfmt "), "audio/wav");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"fLaC"), "audio/x-flac");
|
|
||||||
|
|
||||||
// Video
|
|
||||||
assert_eq!(utils::detect_mimetype(b"RIFF....AVI LIST"), "video/avi");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"....ftyp"), "video/mp4");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\x00\x00\x01\x0B"), "video/mpeg");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"....moov"), "video/quicktime");
|
|
||||||
assert_eq!(utils::detect_mimetype(b"\x1A\x45\xDF\xA3"), "video/webm");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn url_has_protocol() {
|
|
||||||
// Passing
|
|
||||||
assert_eq!(
|
|
||||||
utils::url_has_protocol("mailto:somebody@somewhere.com?subject=hello"),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
assert_eq!(utils::url_has_protocol("tel:5551234567"), true);
|
|
||||||
assert_eq!(
|
|
||||||
utils::url_has_protocol("ftp:user:password@some-ftp-server.com"),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
assert_eq!(utils::url_has_protocol("javascript:void(0)"), true);
|
|
||||||
assert_eq!(utils::url_has_protocol("http://news.ycombinator.com"), true);
|
|
||||||
assert_eq!(utils::url_has_protocol("https://github.com"), true);
|
|
||||||
assert_eq!(
|
|
||||||
utils::url_has_protocol("MAILTO:somebody@somewhere.com?subject=hello"),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// Failing
|
|
||||||
assert_eq!(
|
|
||||||
utils::url_has_protocol("//some-hostname.com/some-file.html"),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
utils::url_has_protocol("some-hostname.com/some-file.html"),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert_eq!(utils::url_has_protocol("/some-file.html"), false);
|
|
||||||
assert_eq!(utils::url_has_protocol(""), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_file_url() {
|
|
||||||
// Passing
|
|
||||||
assert!(utils::is_file_url(
|
|
||||||
"file:///home/user/Websites/my-website/index.html"
|
|
||||||
));
|
|
||||||
assert!(utils::is_file_url(
|
|
||||||
"file:///C:/Documents%20and%20Settings/user/Websites/my-website/assets/images/logo.png"
|
|
||||||
));
|
|
||||||
assert!(utils::is_file_url(
|
|
||||||
"file:\\\\\\home\\user\\Websites\\my-website\\index.html"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Failing
|
|
||||||
assert!(!utils::is_file_url("//kernel.org"));
|
|
||||||
assert!(!utils::is_file_url("./index.html"));
|
|
||||||
assert!(!utils::is_file_url("some-local-page.htm"));
|
|
||||||
assert!(!utils::is_file_url("https://1.2.3.4:80/www/index.html"));
|
|
||||||
assert!(!utils::is_file_url(
|
|
||||||
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_http_url() {
|
|
||||||
// Passing
|
|
||||||
assert!(utils::is_http_url("https://www.rust-lang.org/"));
|
|
||||||
assert!(utils::is_http_url("http://kernel.org"));
|
|
||||||
assert!(utils::is_http_url("http:\\\\freebsd.org\\"));
|
|
||||||
|
|
||||||
// Failing
|
|
||||||
assert!(!utils::is_http_url("//kernel.org"));
|
|
||||||
assert!(!utils::is_http_url("./index.html"));
|
|
||||||
assert!(!utils::is_http_url("some-local-page.htm"));
|
|
||||||
assert!(!utils::is_http_url("ftp://1.2.3.4/www/index.html"));
|
|
||||||
assert!(!utils::is_http_url(
|
|
||||||
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn resolve_url() -> Result<(), ParseError> {
|
|
||||||
let resolved_url = utils::resolve_url("https://www.kernel.org", "../category/signatures.html")?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/category/signatures.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url("https://www.kernel.org", "category/signatures.html")?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/category/signatures.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"saved_page.htm",
|
|
||||||
"https://www.kernel.org/category/signatures.html",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/category/signatures.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"https://www.kernel.org",
|
|
||||||
"//www.kernel.org/theme/images/logos/tux.png",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/theme/images/logos/tux.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"https://www.kernel.org",
|
|
||||||
"//another-host.org/theme/images/logos/tux.png",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://another-host.org/theme/images/logos/tux.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"https://www.kernel.org/category/signatures.html",
|
|
||||||
"/theme/images/logos/tux.png",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/theme/images/logos/tux.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"https://www.w3schools.com/html/html_iframe.asp",
|
|
||||||
"default.asp",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.w3schools.com/html/default.asp"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
|
|
||||||
"https://www.kernel.org/category/signatures.html",
|
|
||||||
)?;
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"https://www.kernel.org/category/signatures.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
|
|
||||||
"//www.w3schools.com/html/html_iframe.asp",
|
|
||||||
)
|
|
||||||
.unwrap_or(str!());
|
|
||||||
assert_eq!(resolved_url.as_str(), "");
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"file:///home/user/Websites/my-website/index.html",
|
|
||||||
"assets/images/logo.png",
|
|
||||||
)
|
|
||||||
.unwrap_or(str!());
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"file:///home/user/Websites/my-website/assets/images/logo.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
let resolved_url = utils::resolve_url(
|
|
||||||
"file:\\\\\\home\\user\\Websites\\my-website\\index.html",
|
|
||||||
"assets\\images\\logo.png",
|
|
||||||
)
|
|
||||||
.unwrap_or(str!());
|
|
||||||
assert_eq!(
|
|
||||||
resolved_url.as_str(),
|
|
||||||
"file:///home/user/Websites/my-website/assets/images/logo.png"
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn is_data_url() {
|
|
||||||
// Passing
|
|
||||||
assert!(utils::is_data_url(
|
|
||||||
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
|
||||||
));
|
|
||||||
|
|
||||||
// Failing
|
|
||||||
assert!(!utils::is_data_url("https://kernel.org"));
|
|
||||||
assert!(!utils::is_data_url("//kernel.org"));
|
|
||||||
assert!(!utils::is_data_url(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn clean_url() {
|
|
||||||
assert_eq!(
|
|
||||||
utils::clean_url("https://somewhere.com/font.eot#iefix"),
|
|
||||||
"https://somewhere.com/font.eot"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
utils::clean_url("https://somewhere.com/font.eot#"),
|
|
||||||
"https://somewhere.com/font.eot"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
utils::clean_url("https://somewhere.com/font.eot?#"),
|
|
||||||
"https://somewhere.com/font.eot"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn data_url_to_text() {
|
|
||||||
assert_eq!(
|
|
||||||
utils::data_url_to_text("data:text/html;base64,V29yayBleHBhbmRzIHNvIGFzIHRvIGZpbGwgdGhlIHRpbWUgYXZhaWxhYmxlIGZvciBpdHMgY29tcGxldGlvbg=="),
|
|
||||||
"Work expands so as to fill the time available for its completion"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
utils::data_url_to_text(
|
|
||||||
"data:text/html;utf8,Work expands so as to fill the time available for its completion"
|
|
||||||
),
|
|
||||||
"Work expands so as to fill the time available for its completion"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
utils::data_url_to_text(
|
|
||||||
"data:text/html,Work expands so as to fill the time available for its completion"
|
|
||||||
),
|
|
||||||
"Work expands so as to fill the time available for its completion"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
utils::data_url_to_text(
|
|
||||||
" data:text/html;charset=utf-8,Work expands so as to fill the time available for its completion "
|
|
||||||
),
|
|
||||||
"Work expands so as to fill the time available for its completion"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn decode_url() {
|
|
||||||
assert_eq!(
|
|
||||||
utils::decode_url(str!(
|
|
||||||
"%E6%A4%9C%E3%83%92%E3%83%A0%E8%A7%A3%E5%A1%97%E3%82%83%E3%83%83%20%3D%20%E3%82%B5"
|
|
||||||
)),
|
|
||||||
"検ヒム解塗ゃッ = サ"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(utils::decode_url(str!("%20 %20")), " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn retrieve_asset() {
|
|
||||||
let cache = &mut HashMap::new();
|
|
||||||
let client = Client::new();
|
|
||||||
|
|
||||||
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" };
|
|
||||||
|
|
||||||
// If both source and target are data URLs,
|
|
||||||
// ensure the result contains target data URL
|
|
||||||
let (data, final_url) = utils::retrieve_asset(
|
|
||||||
cache,
|
|
||||||
&client,
|
|
||||||
"data:text/html;base64,SoUrCe",
|
|
||||||
"data:text/html;base64,TaRgEt",
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&data, "data:text/html;base64,TaRgEt");
|
|
||||||
assert_eq!(&final_url, "data:text/html;base64,TaRgEt");
|
|
||||||
|
|
||||||
// Media type parameter should not influence data URLs
|
|
||||||
let (data, final_url) = utils::retrieve_asset(
|
|
||||||
cache,
|
|
||||||
&client,
|
|
||||||
"data:text/html;base64,SoUrCe",
|
|
||||||
"data:text/html;base64,TaRgEt",
|
|
||||||
true,
|
|
||||||
"image/png",
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&data, "data:text/html;base64,TaRgEt");
|
|
||||||
assert_eq!(&final_url, "data:text/html;base64,TaRgEt");
|
|
||||||
|
|
||||||
// Inclusion of local assets from data URL sources should not be allowed
|
|
||||||
let (data, final_url) = utils::retrieve_asset(
|
|
||||||
cache,
|
|
||||||
&client,
|
|
||||||
"data:text/html;base64,SoUrCe",
|
|
||||||
"file:///etc/passwd",
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&data, "");
|
|
||||||
assert_eq!(&final_url, "");
|
|
||||||
|
|
||||||
// Inclusion of local assets from remote sources should not be allowed
|
|
||||||
let (data, final_url) = utils::retrieve_asset(
|
|
||||||
cache,
|
|
||||||
&client,
|
|
||||||
"https://kernel.org/",
|
|
||||||
"file:///etc/passwd",
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&data, "");
|
|
||||||
assert_eq!(&final_url, "");
|
|
||||||
|
|
||||||
// Inclusion of local assets from local sources should be allowed
|
|
||||||
let cwd = env::current_dir().unwrap();
|
|
||||||
let (data, final_url) = utils::retrieve_asset(
|
|
||||||
cache,
|
|
||||||
&client,
|
|
||||||
&format!(
|
|
||||||
"{file}{cwd}/src/tests/data/local-file.html",
|
|
||||||
file = file_url_protocol,
|
|
||||||
cwd = cwd.to_str().unwrap()
|
|
||||||
),
|
|
||||||
&format!(
|
|
||||||
"{file}{cwd}/src/tests/data/local-script.js",
|
|
||||||
file = file_url_protocol,
|
|
||||||
cwd = cwd.to_str().unwrap()
|
|
||||||
),
|
|
||||||
true,
|
|
||||||
"application/javascript",
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(&data, "data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==");
|
|
||||||
assert_eq!(
|
|
||||||
&final_url,
|
|
||||||
&format!(
|
|
||||||
"{file}{cwd}/src/tests/data/local-script.js",
|
|
||||||
file = file_url_protocol,
|
|
||||||
cwd = cwd.to_str().unwrap()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_removes_fragment() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::clean_url("https://somewhere.com/font.eot#iefix"),
|
||||||
|
"https://somewhere.com/font.eot"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_removes_empty_fragment() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::clean_url("https://somewhere.com/font.eot#"),
|
||||||
|
"https://somewhere.com/font.eot"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_removes_empty_query_and_empty_fragment() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::clean_url("https://somewhere.com/font.eot?#"),
|
||||||
|
"https://somewhere.com/font.eot"
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_encode_string_with_specific_media_type() {
|
||||||
|
let mime = "application/javascript";
|
||||||
|
let data = "var word = 'hello';\nalert(word);\n";
|
||||||
|
let data_url = utils::data_to_data_url(mime, data.as_bytes());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&data_url,
|
||||||
|
"data:application/javascript;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK"
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_parse_text_html_base64() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::data_url_to_text("data:text/html;base64,V29yayBleHBhbmRzIHNvIGFzIHRvIGZpbGwgdGhlIHRpbWUgYXZhaWxhYmxlIGZvciBpdHMgY29tcGxldGlvbg=="),
|
||||||
|
"Work expands so as to fill the time available for its completion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_parse_text_html_utf8() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::data_url_to_text(
|
||||||
|
"data:text/html;utf8,Work expands so as to fill the time available for its completion"
|
||||||
|
),
|
||||||
|
"Work expands so as to fill the time available for its completion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_parse_text_html_plaintext() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::data_url_to_text(
|
||||||
|
"data:text/html,Work expands so as to fill the time available for its completion"
|
||||||
|
),
|
||||||
|
"Work expands so as to fill the time available for its completion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_parse_text_html_charset_utf_8_between_two_whitespaces() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::data_url_to_text(
|
||||||
|
" data:text/html;charset=utf-8,Work expands so as to fill the time available for its completion "
|
||||||
|
),
|
||||||
|
"Work expands so as to fill the time available for its completion"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_just_word_data() {
|
||||||
|
assert_eq!(utils::data_url_to_text("data"), "");
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_decode_unicode_characters() {
|
||||||
|
assert_eq!(
|
||||||
|
utils::decode_url(str!(
|
||||||
|
"%E6%A4%9C%E3%83%92%E3%83%A0%E8%A7%A3%E5%A1%97%E3%82%83%E3%83%83%20%3D%20%E3%82%B5"
|
||||||
|
)),
|
||||||
|
"検ヒム解塗ゃッ = サ"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_decode_whitespaces() {
|
||||||
|
assert_eq!(utils::decode_url(str!("%20 %20")), " ");
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_image_media_types() {
|
||||||
|
assert_eq!(utils::detect_media_type(b"GIF87a"), "image/gif");
|
||||||
|
assert_eq!(utils::detect_media_type(b"GIF89a"), "image/gif");
|
||||||
|
assert_eq!(utils::detect_media_type(b"\xFF\xD8\xFF"), "image/jpeg");
|
||||||
|
assert_eq!(
|
||||||
|
utils::detect_media_type(b"\x89PNG\x0D\x0A\x1A\x0A"),
|
||||||
|
"image/png"
|
||||||
|
);
|
||||||
|
assert_eq!(utils::detect_media_type(b"<?xml "), "image/svg+xml");
|
||||||
|
assert_eq!(utils::detect_media_type(b"<svg "), "image/svg+xml");
|
||||||
|
assert_eq!(utils::detect_media_type(b"RIFF....WEBPVP8 "), "image/webp");
|
||||||
|
assert_eq!(
|
||||||
|
utils::detect_media_type(b"\x00\x00\x01\x00"),
|
||||||
|
"image/x-icon"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_audio_media_types() {
|
||||||
|
assert_eq!(utils::detect_media_type(b"ID3"), "audio/mpeg");
|
||||||
|
assert_eq!(utils::detect_media_type(b"\xFF\x0E"), "audio/mpeg");
|
||||||
|
assert_eq!(utils::detect_media_type(b"\xFF\x0F"), "audio/mpeg");
|
||||||
|
assert_eq!(utils::detect_media_type(b"OggS"), "audio/ogg");
|
||||||
|
assert_eq!(utils::detect_media_type(b"RIFF....WAVEfmt "), "audio/wav");
|
||||||
|
assert_eq!(utils::detect_media_type(b"fLaC"), "audio/x-flac");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_video_media_types() {
|
||||||
|
assert_eq!(utils::detect_media_type(b"RIFF....AVI LIST"), "video/avi");
|
||||||
|
assert_eq!(utils::detect_media_type(b"....ftyp"), "video/mp4");
|
||||||
|
assert_eq!(utils::detect_media_type(b"\x00\x00\x01\x0B"), "video/mpeg");
|
||||||
|
assert_eq!(utils::detect_media_type(b"....moov"), "video/quicktime");
|
||||||
|
assert_eq!(utils::detect_media_type(b"\x1A\x45\xDF\xA3"), "video/webm");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_unknown_media_type() {
|
||||||
|
assert_eq!(utils::detect_media_type(b"abcdef0123456789"), "");
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_data_url_text_html() {
|
||||||
|
assert!(utils::is_data_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_data_url_no_media_type() {
|
||||||
|
assert!(utils::is_data_url(
|
||||||
|
"data:;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_https_url() {
|
||||||
|
assert!(!utils::is_data_url("https://kernel.org"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_no_protocol_url() {
|
||||||
|
assert!(!utils::is_data_url("//kernel.org"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_empty_string() {
|
||||||
|
assert!(!utils::is_data_url(""));
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_unix_file_url() {
|
||||||
|
assert!(utils::is_file_url(
|
||||||
|
"file:///home/user/Websites/my-website/index.html"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_windows_file_url() {
|
||||||
|
assert!(utils::is_file_url(
|
||||||
|
"file:///C:/Documents%20and%20Settings/user/Websites/my-website/assets/images/logo.png"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_unix_url_with_backslashes() {
|
||||||
|
assert!(utils::is_file_url(
|
||||||
|
"file:\\\\\\home\\user\\Websites\\my-website\\index.html"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_windows_file_url_with_backslashes() {
|
||||||
|
assert!(utils::is_file_url(
|
||||||
|
"file:\\\\\\C:\\Documents%20and%20Settings\\user\\Websites\\my-website\\assets\\images\\logo.png"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_url_with_no_protocl() {
|
||||||
|
assert!(!utils::is_file_url("//kernel.org"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_dot_slash_filename() {
|
||||||
|
assert!(!utils::is_file_url("./index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_just_filename() {
|
||||||
|
assert!(!utils::is_file_url("some-local-page.htm"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_https_ip_port_url() {
|
||||||
|
assert!(!utils::is_file_url("https://1.2.3.4:80/www/index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_data_url() {
|
||||||
|
assert!(!utils::is_file_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_just_word_file() {
|
||||||
|
assert!(!utils::is_file_url("file"));
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_http_url() {
|
||||||
|
assert!(utils::is_http_url("http://kernel.org"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_https_url() {
|
||||||
|
assert!(utils::is_http_url("https://www.rust-lang.org/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_http_url_with_backslashes() {
|
||||||
|
assert!(utils::is_http_url("http:\\\\freebsd.org\\"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_url_with_no_protocol() {
|
||||||
|
assert!(!utils::is_http_url("//kernel.org"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_dot_slash_filename() {
|
||||||
|
assert!(!utils::is_http_url("./index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_just_filename() {
|
||||||
|
assert!(!utils::is_http_url("some-local-page.htm"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_https_ip_port_url() {
|
||||||
|
assert!(!utils::is_http_url("ftp://1.2.3.4/www/index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_data_url() {
|
||||||
|
assert!(!utils::is_http_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
|
||||||
|
));
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
mod clean_url;
|
||||||
|
mod data_to_data_url;
|
||||||
|
mod data_url_to_text;
|
||||||
|
mod decode_url;
|
||||||
|
mod detect_media_type;
|
||||||
|
mod is_data_url;
|
||||||
|
mod is_file_url;
|
||||||
|
mod is_http_url;
|
||||||
|
mod resolve_url;
|
||||||
|
mod retrieve_asset;
|
||||||
|
mod url_has_protocol;
|
|
@ -0,0 +1,177 @@
|
||||||
|
use crate::utils;
|
||||||
|
use url::ParseError;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_https_to_level_up_relative() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url("https://www.kernel.org", "../category/signatures.html")?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.kernel.org/category/signatures.html"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_just_filename_to_full_https_url() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"saved_page.htm",
|
||||||
|
"https://www.kernel.org/category/signatures.html",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.kernel.org/category/signatures.html"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_https_url_to_url_with_no_protocol() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"https://www.kernel.org",
|
||||||
|
"//www.kernel.org/theme/images/logos/tux.png",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.kernel.org/theme/images/logos/tux.png"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_https_url_to_url_with_no_protocol_and_on_different_hostname(
|
||||||
|
) -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"https://www.kernel.org",
|
||||||
|
"//another-host.org/theme/images/logos/tux.png",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://another-host.org/theme/images/logos/tux.png"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_https_url_to_relative_root_path() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"https://www.kernel.org/category/signatures.html",
|
||||||
|
"/theme/images/logos/tux.png",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.kernel.org/theme/images/logos/tux.png"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_https_to_just_filename() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"https://www.w3schools.com/html/html_iframe.asp",
|
||||||
|
"default.asp",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.w3schools.com/html/default.asp"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_data_url_to_https() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
|
||||||
|
"https://www.kernel.org/category/signatures.html",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"https://www.kernel.org/category/signatures.html"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_file_url_to_relative_path() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"file:///home/user/Websites/my-website/index.html",
|
||||||
|
"assets/images/logo.png",
|
||||||
|
)
|
||||||
|
.unwrap_or(str!());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"file:///home/user/Websites/my-website/assets/images/logo.png"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_file_url_to_relative_path_with_backslashes() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"file:\\\\\\home\\user\\Websites\\my-website\\index.html",
|
||||||
|
"assets\\images\\logo.png",
|
||||||
|
)
|
||||||
|
.unwrap_or(str!());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
resolved_url.as_str(),
|
||||||
|
"file:///home/user/Websites/my-website/assets/images/logo.png"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_from_data_url_to_file_url() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
|
||||||
|
"file:///etc/passwd",
|
||||||
|
)
|
||||||
|
.unwrap_or(str!());
|
||||||
|
|
||||||
|
assert_eq!(resolved_url.as_str(), "file:///etc/passwd");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_from_data_url_to_url_with_no_protocol() -> Result<(), ParseError> {
|
||||||
|
let resolved_url = utils::resolve_url(
|
||||||
|
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
|
||||||
|
"//www.w3schools.com/html/html_iframe.asp",
|
||||||
|
)
|
||||||
|
.unwrap_or(str!());
|
||||||
|
|
||||||
|
assert_eq!(resolved_url.as_str(), "");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
use crate::utils;
|
||||||
|
use reqwest::blocking::Client;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_read_data_url() {
|
||||||
|
let cache = &mut HashMap::new();
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
// If both source and target are data URLs,
|
||||||
|
// ensure the result contains target data URL
|
||||||
|
let (retrieved_data, final_url) = utils::retrieve_asset(
|
||||||
|
cache,
|
||||||
|
&client,
|
||||||
|
"data:text/html;base64,SoUrCe",
|
||||||
|
"data:text/html;base64,TaRgEt",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(&retrieved_data, "data:text/html;base64,TaRgEt");
|
||||||
|
assert_eq!(&final_url, "data:text/html;base64,TaRgEt");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_read_data_url_ignore_suggested_media_type() {
|
||||||
|
let cache = &mut HashMap::new();
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
// Media type parameter should not influence data URLs
|
||||||
|
let (data, final_url) = utils::retrieve_asset(
|
||||||
|
cache,
|
||||||
|
&client,
|
||||||
|
"data:text/html;base64,SoUrCe",
|
||||||
|
"data:text/html;base64,TaRgEt",
|
||||||
|
true,
|
||||||
|
"image/png",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(&data, "data:text/html;base64,TaRgEt");
|
||||||
|
assert_eq!(&final_url, "data:text/html;base64,TaRgEt");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_read_local_file_with_file_url_parent() {
|
||||||
|
let cache = &mut HashMap::new();
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" };
|
||||||
|
|
||||||
|
// Inclusion of local assets from local sources should be allowed
|
||||||
|
let cwd = env::current_dir().unwrap();
|
||||||
|
let (data, final_url) = utils::retrieve_asset(
|
||||||
|
cache,
|
||||||
|
&client,
|
||||||
|
&format!(
|
||||||
|
"{file}{cwd}/src/tests/data/local-file.html",
|
||||||
|
file = file_url_protocol,
|
||||||
|
cwd = cwd.to_str().unwrap()
|
||||||
|
),
|
||||||
|
&format!(
|
||||||
|
"{file}{cwd}/src/tests/data/local-script.js",
|
||||||
|
file = file_url_protocol,
|
||||||
|
cwd = cwd.to_str().unwrap()
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
"application/javascript",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(&data, "data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==");
|
||||||
|
assert_eq!(
|
||||||
|
&final_url,
|
||||||
|
&format!(
|
||||||
|
"{file}{cwd}/src/tests/data/local-script.js",
|
||||||
|
file = file_url_protocol,
|
||||||
|
cwd = cwd.to_str().unwrap()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_read_local_file_with_data_url_parent() {
|
||||||
|
let cache = &mut HashMap::new();
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
// Inclusion of local assets from data URL sources should not be allowed
|
||||||
|
let (data, final_url) = utils::retrieve_asset(
|
||||||
|
cache,
|
||||||
|
&client,
|
||||||
|
"data:text/html;base64,SoUrCe",
|
||||||
|
"file:///etc/passwd",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(&data, "");
|
||||||
|
assert_eq!(&final_url, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_read_local_file_with_https_parent() {
|
||||||
|
let cache = &mut HashMap::new();
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
// Inclusion of local assets from remote sources should not be allowed
|
||||||
|
let (data, final_url) = utils::retrieve_asset(
|
||||||
|
cache,
|
||||||
|
&client,
|
||||||
|
"https://kernel.org/",
|
||||||
|
"file:///etc/passwd",
|
||||||
|
true,
|
||||||
|
"",
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(&data, "");
|
||||||
|
assert_eq!(&final_url, "");
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
|
||||||
|
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_mailto() {
|
||||||
|
assert!(utils::url_has_protocol(
|
||||||
|
"mailto:somebody@somewhere.com?subject=hello"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_tel() {
|
||||||
|
assert!(utils::url_has_protocol("tel:5551234567"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_ftp_no_slashes() {
|
||||||
|
assert!(utils::url_has_protocol("ftp:some-ftp-server.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_ftp_with_credentials() {
|
||||||
|
assert!(utils::url_has_protocol(
|
||||||
|
"ftp://user:password@some-ftp-server.com"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_javascript() {
|
||||||
|
assert!(utils::url_has_protocol("javascript:void(0)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_http() {
|
||||||
|
assert!(utils::url_has_protocol("http://news.ycombinator.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_https() {
|
||||||
|
assert!(utils::url_has_protocol("https://github.com"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn passing_mailto_uppercase() {
|
||||||
|
assert!(utils::url_has_protocol(
|
||||||
|
"MAILTO:somebody@somewhere.com?subject=hello"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
|
||||||
|
// ██╔════╝██╔══██╗██║██║ ██║████╗ ██║██╔════╝
|
||||||
|
// █████╗ ███████║██║██║ ██║██╔██╗ ██║██║ ███╗
|
||||||
|
// ██╔══╝ ██╔══██║██║██║ ██║██║╚██╗██║██║ ██║
|
||||||
|
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
|
||||||
|
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_url_with_no_protocol() {
|
||||||
|
assert!(!utils::url_has_protocol(
|
||||||
|
"//some-hostname.com/some-file.html"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_relative_path() {
|
||||||
|
assert!(!utils::url_has_protocol("some-hostname.com/some-file.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_relative_to_root_path() {
|
||||||
|
assert!(!utils::url_has_protocol("/some-file.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn failing_empty_string() {
|
||||||
|
assert!(!utils::url_has_protocol(""));
|
||||||
|
}
|
12
src/utils.rs
12
src/utils.rs
|
@ -68,15 +68,15 @@ const MAGIC: [[&[u8]; 2]; 19] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn data_to_data_url(mime: &str, data: &[u8]) -> String {
|
pub fn data_to_data_url(mime: &str, data: &[u8]) -> String {
|
||||||
let mimetype = if mime.is_empty() {
|
let media_type = if mime.is_empty() {
|
||||||
detect_mimetype(data)
|
detect_media_type(data)
|
||||||
} else {
|
} else {
|
||||||
mime.to_string()
|
mime.to_string()
|
||||||
};
|
};
|
||||||
format!("data:{};base64,{}", mimetype, base64::encode(data))
|
format!("data:{};base64,{}", media_type, base64::encode(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detect_mimetype(data: &[u8]) -> String {
|
pub fn detect_media_type(data: &[u8]) -> String {
|
||||||
for item in MAGIC.iter() {
|
for item in MAGIC.iter() {
|
||||||
if data.starts_with(item[0]) {
|
if data.starts_with(item[0]) {
|
||||||
return String::from_utf8(item[1].to_vec()).unwrap();
|
return String::from_utf8(item[1].to_vec()).unwrap();
|
||||||
|
@ -356,7 +356,7 @@ pub fn retrieve_asset(
|
||||||
response.copy_to(&mut data)?;
|
response.copy_to(&mut data)?;
|
||||||
|
|
||||||
// Attempt to obtain MIME type by reading the Content-Type header
|
// Attempt to obtain MIME type by reading the Content-Type header
|
||||||
let mimetype = if mime == "" {
|
let media_type = if mime == "" {
|
||||||
response
|
response
|
||||||
.headers()
|
.headers()
|
||||||
.get(CONTENT_TYPE)
|
.get(CONTENT_TYPE)
|
||||||
|
@ -365,7 +365,7 @@ pub fn retrieve_asset(
|
||||||
} else {
|
} else {
|
||||||
mime
|
mime
|
||||||
};
|
};
|
||||||
let data_url = data_to_data_url(&mimetype, &data);
|
let data_url = data_to_data_url(&media_type, &data);
|
||||||
// Add to cache
|
// Add to cache
|
||||||
cache.insert(new_cache_key, data_url.clone());
|
cache.insert(new_cache_key, data_url.clone());
|
||||||
Ok((data_url, res_url))
|
Ok((data_url, res_url))
|
||||||
|
|
Loading…
Reference in New Issue