feat(html/minifier): Compress javascript: URLs (#6185)

This commit is contained in:
Alexander Akait 2022-10-18 17:15:43 +03:00 committed by GitHub
parent a81cc9ac88
commit 8f00d1a934
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 7 deletions

View File

@ -173,6 +173,8 @@ static ALLOW_TO_TRIM_HTML_ATTRIBUTES: &[(&str, &str)] = &[
("object", "usemap"), ("object", "usemap"),
]; ];
static ALLOW_TO_TRIM_SVG_ATTRIBUTES: &[(&str, &str)] = &[("a", "href")];
static COMMA_SEPARATED_HTML_ATTRIBUTES: &[(&str, &str)] = &[ static COMMA_SEPARATED_HTML_ATTRIBUTES: &[(&str, &str)] = &[
("img", "srcset"), ("img", "srcset"),
("source", "srcset"), ("source", "srcset"),
@ -398,6 +400,9 @@ impl Minifier<'_> {
Namespace::HTML => { Namespace::HTML => {
ALLOW_TO_TRIM_HTML_ATTRIBUTES.contains(&(&element.tag_name, attribute_name)) ALLOW_TO_TRIM_HTML_ATTRIBUTES.contains(&(&element.tag_name, attribute_name))
} }
Namespace::SVG => {
ALLOW_TO_TRIM_SVG_ATTRIBUTES.contains(&(&element.tag_name, attribute_name))
}
_ => false, _ => false,
} }
} }
@ -658,6 +663,16 @@ impl Minifier<'_> {
} }
} }
fn is_javascript_url_element(&self, element: &Element) -> bool {
match (element.namespace, &element.tag_name) {
(Namespace::HTML | Namespace::SVG, &js_word!("a")) => return true,
(Namespace::HTML, &js_word!("iframe")) => return true,
_ => {}
}
false
}
fn is_preserved_comment(&self, data: &str) -> bool { fn is_preserved_comment(&self, data: &str) -> bool {
if let Some(preserve_comments) = &self.options.preserve_comments { if let Some(preserve_comments) = &self.options.preserve_comments {
return preserve_comments.iter().any(|regex| regex.is_match(data)); return preserve_comments.iter().any(|regex| regex.is_match(data));
@ -2419,18 +2434,42 @@ impl VisitMut for Minifier<'_> {
_ if self.is_trimable_separated_attribute(current_element, &n.name) => { _ if self.is_trimable_separated_attribute(current_element, &n.name) => {
let mut value = value.to_string(); let mut value = value.to_string();
let fallback = |n: &mut Attribute| {
if self.options.normalize_attributes { if self.options.normalize_attributes {
value = value.trim().to_string(); n.value = Some(value.trim().into());
} }
};
if self.need_minify_css() && n.name == js_word!("style") && !value.is_empty() { if self.need_minify_css() && n.name == js_word!("style") && !value.is_empty() {
if let Some(minified) = let value = value.trim();
self.minify_css(value, CssMinificationMode::ListOfDeclarations)
if let Some(minified) = self
.minify_css(value.to_string(), CssMinificationMode::ListOfDeclarations)
{ {
n.value = Some(minified.into()); n.value = Some(minified.into());
} else {
fallback(n);
}
} else if self.need_minify_js()
&& self.is_javascript_url_element(current_element)
{
if value.trim().to_lowercase().starts_with("javascript:") {
value = value.trim().chars().skip(11).collect();
if let Some(minified) = self.minify_js(value, false, true) {
let mut with_javascript =
String::with_capacity(11 + minified.len());
with_javascript.push_str("javascript:");
with_javascript.push_str(&minified);
n.value = Some(with_javascript.into());
} }
} else { } else {
n.value = Some(value.into()); fallback(n);
}
} else {
fallback(n);
} }
} }
_ if self.options.minify_additional_attributes.is_some() => { _ if self.options.minify_additional_attributes.is_some() => {

View File

@ -0,0 +1,3 @@
{
"normalizeAttributes": false
}

View File

@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<a href=" javascript: alert( 'test' ) ">a</a>
<a href=" JAVASCRIPT: alert( 'test' ) ">b</a>
<iframe src="javascript: alert( 'test' ) " frameborder="0"></iframe>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- A link around a shape -->
<a href="javascript: alert( 'test' ) ">
<circle cx="50" cy="40" r="35" />
</a>
<!-- A link around a text -->
<a href=" javascript: alert( 'test' ) ">
<text x="50" y="90" text-anchor="middle">&lt;circle&gt;</text>
</a>
</svg>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!doctype html><html lang=en><title>Document</title><a href='javascript:alert("test")'>a</a>
<a href='javascript:alert("test")'>b</a>
<iframe src='javascript:alert("test")' frameborder=0></iframe>
<svg viewBox="0 0 100 100">
<a href='javascript:alert("test")'>
<circle cx=50 cy=40 r=35 />
</a>
<a href='javascript:alert("test")'>
<text x=50 y=90 text-anchor=middle>&lt;circle></text>
</a>
</svg>

View File

@ -0,0 +1,22 @@
<!doctype html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<a href=" javascript: alert( 'test' ) ">a</a>
<a href=" JAVASCRIPT: alert( 'test' ) ">b</a>
<a href=" JAVASCRIPT: broken;;( ">b</a>
<iframe src="javascript: alert( 'test' ) " frameborder="0"></iframe>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<!-- A link around a shape -->
<a href="javascript: alert( 'test' ) ">
<circle cx="50" cy="40" r="35" />
</a>
<!-- A link around a text -->
<a href=" javascript: alert( 'test' ) ">
<text x="50" y="90" text-anchor="middle">&lt;circle&gt;</text>
</a>
</svg>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!doctype html><html lang=en><title>Document</title><a href='javascript:alert("test")'>a</a>
<a href='javascript:alert("test")'>b</a>
<a href=" JAVASCRIPT: broken;;( ">b</a>
<iframe src='javascript:alert("test")' frameborder=0></iframe>
<svg viewBox="0 0 100 100">
<a href='javascript:alert("test")'>
<circle cx=50 cy=40 r=35 />
</a>
<a href='javascript:alert("test")'>
<text x=50 y=90 text-anchor=middle>&lt;circle></text>
</a>
</svg>

View File

@ -286,7 +286,7 @@
</svg> </svg>
<svg> <svg>
<a href=" test.html " ondragexit='alert("testtest")' rel="nofollow noindex">Test</a> <a href=test.html ondragexit='alert("testtest")' rel="nofollow noindex">Test</a>
</svg> </svg>
<svg viewBox="0 0 100 100" width=160 height=60 y=30> <svg viewBox="0 0 100 100" width=160 height=60 y=30>