Handle cases where closing tags are out of order, causing extra closing
tags that are added to break the page.
Patch by fu.
diffs (122 lines):
diff -r 1ef62983473f -r 943d1d3d0bc4 cgi-bin/LJ/CleanHTML.pm
--- a/cgi-bin/LJ/CleanHTML.pm Fri Dec 17 15:06:28 2010 +0800
+++ b/cgi-bin/LJ/CleanHTML.pm Fri Dec 17 15:27:29 2010 +0800
@@ -237,6 +237,8 @@ sub clean
my $capturing_during_eat; # if we save all tokens that happen inside the
eating.
my @capture = (); # if so, they go here
+
+ my @tagstack = (); # so we can make sure that tags are closed properly/in
order
my $form_tag = {
input => 1,
@@ -886,6 +888,12 @@ sub clean
}
}
+ # we have all this previous logic which makes us
+ # not automatically close tags inside tables
+ # so rather than mess with it, let's just ignore
those
+ # and only deal with non-self-closing tags
+ # which are not in a table
+ push @tagstack, $tag unless $slashclose ||
@tablescope;
}
else { $newdata .= ">"; }
}
@@ -970,7 +978,6 @@ sub clean
if ($allow && ! $remove{$tag})
{
-
if ($opts->{'tablecheck'}) {
$allow = 0 if
@@ -983,6 +990,14 @@ sub clean
}
if ($allow && ! ($opts->{'noearlyclose'} && !
$opencount{$tag})) {
+
+ unless ( @tablescope ) {
+ my $close;
+ while ( ( $close = pop @tagstack ) && $close ne
$tag ) {
+ $opencount{$close}--;
+ $newdata .= "</$close>";
+ }
+ }
# maintain current table scope
if ($opts->{'tablecheck'}) {
@@ -997,8 +1012,10 @@ sub clean
}
}
- $newdata .= "</$tag>";
- $opencount{$tag}--;
+ if ( $opencount{$tag} ) {
+ $newdata .= "</$tag>";
+ $opencount{$tag}--;
+ }
} else {
$newdata .= "</$tag>";
}
diff -r 1ef62983473f -r 943d1d3d0bc4 t/clean-event.t
--- a/t/clean-event.t Fri Dec 17 15:06:28 2010 +0800
+++ b/t/clean-event.t Fri Dec 17 15:27:29 2010 +0800
@@ -16,6 +16,49 @@ my $clean = sub {
LJ::CleanHTML::clean_event(\$orig_post, $opts);
};
+note("malformed html");
+$orig_post = qq{<div><span>abc</div>};
+$clean_post = qq{<div><span>abc</span></div>};
+$clean->();
+is( $orig_post, $clean_post, "Inner tag isn't closed" );
+
+$orig_post = qq{<div><table><tr><td></td></tr></table><span></div>};
+$clean_post = qq{<div><table><tr><td></td></tr></table><span></span></div>};
+$clean->();
+is( $orig_post, $clean_post, "Tag outside a table isn't closed" );
+
+# this is a bit weird; we don't want to mess with tags in tables
+# so we just close it after, leading to this HTML
+$orig_post = qq{<div><table><tr><td><span></td></tr></table></div>};
+$clean_post = qq{<div><table><tr><td><span></td></tr></table></div></span>};
+$clean->();
+is( $orig_post, $clean_post, "Non-table-related tag inside a table is open" );
+
+$orig_post = qq{<div><table><tr><td></tr></table></div>};
+$clean_post = qq{<div><table><tr><td></tr></table></div>};
+$clean->();
+is( $orig_post, $clean_post, "Table-related-tag inside a table is open" );
+
+$orig_post = qq{<div><img /></div>};
+$clean_post = qq{<div><img /></div>};
+$clean->();
+is( $orig_post, $clean_post, "Slash-closed tag" );
+
+$orig_post = qq{<div><span>};
+$clean_post = qq{<div><span></span></div>};
+$clean->();
+is( $orig_post, $clean_post, "No closing tags" );
+
+# in this case, we consider the <span> within the div as unclosed
+# and the closing </span> as extra/unrelated.
+# Therefore, we close the opening tag (which needs to be closed)
+# and escape the closing tag (which has no opening tag)
+$orig_post = qq{<div><span></div></span>};
+$clean_post = qq{<div><span></span></div></span>};
+$clean->();
+is( $orig_post, $clean_post, "Wrong closing tag order" );
+
+note("unwanted tags and attributes");
# remove header tags
$orig_post = qq{<h1>test</h1>testing this<h2>testing again</h2>};
$clean_post = qq{testtesting thistesting again};
@@ -64,6 +107,7 @@ ok($orig_post =~ /^$clean_post$/, "CSS c
$clean->({ remove_fonts => 1, remove_sizes => 1 });
ok($orig_post =~ /^$clean_post$/, "CSS fonts and sizes removed");
+note("cut tags");
# get cut text
my $cut_text;
my $entry_text = qq{<cut text="first">111</cut><cut text="second">2222</cut>};
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog