1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

Fix an issue where the "%%%" parser could match too many lines in unterminated blocks

Summary: Fixes T13530. The block parser could match too many lines in an unterminated "%%%" literal block. Adjust the logic to stop doing this (and hopefully be a little easier to read).

Test Plan: Added a failing test, made it pass.

Maniphest Tasks: T13530

Differential Revision: https://secure.phabricator.com/D21208
This commit is contained in:
epriestley 2020-05-03 09:13:13 -07:00
parent b2cfcda114
commit 6f09edeb91
3 changed files with 58 additions and 34 deletions

View file

@ -22,51 +22,69 @@ final class PhutilRemarkupLiteralBlockRule extends PhutilRemarkupBlockRule {
// output text and assists automated escaping of blocks coming into the // output text and assists automated escaping of blocks coming into the
// system. // system.
$num_lines = 0; $start_pattern = '(^\s*%%%)';
while (preg_match('/^\s*%%%/', $lines[$cursor])) { $end_pattern = '(%%%\s*$)';
$num_lines++; $trivial_pattern = '(^\s*%%%\s*$)';
// If the line has ONLY "%%%", the block opener doesn't get to double if (!preg_match($start_pattern, $lines[$cursor])) {
// up as a block terminator. return 0;
if (preg_match('/^\s*%%%\s*\z/', $lines[$cursor])) {
$num_lines++;
$cursor++;
} }
while (isset($lines[$cursor])) { $start_cursor = $cursor;
if (!preg_match('/%%%\s*$/', $lines[$cursor])) {
$num_lines++;
$cursor++;
continue;
}
break;
}
$cursor++;
$found_empty = false; $found_empty = false;
while (isset($lines[$cursor])) { $block_start = null;
if (!strlen(trim($lines[$cursor]))) { while (true) {
$num_lines++; if (!isset($lines[$cursor])) {
break;
}
$line = $lines[$cursor];
if ($block_start === null) {
$is_start = preg_match($start_pattern, $line);
// If we've matched a block and then consumed one or more empty lines
// after it, stop merging more blocks into the match.
if ($found_empty) {
break;
}
if ($is_start) {
$block_start = $cursor;
}
}
if ($block_start !== null) {
$is_end = preg_match($end_pattern, $line);
// If a line contains only "%%%", it will match both the start and
// end patterns, but it only counts as a block start.
if ($is_end && ($cursor === $block_start)) {
$is_trivial = preg_match($trivial_pattern, $line);
if ($is_trivial) {
$is_end = false;
}
}
if ($is_end) {
$block_start = null;
$cursor++; $cursor++;
$found_empty = true;
continue; continue;
} }
break;
} }
if ($found_empty) { if ($block_start === null) {
// If there's an empty line after the block, stop merging blocks. if (strlen(trim($line))) {
break;
}
if (!isset($lines[$cursor])) {
// If we're at the end of the input, stop looking for more lines.
break; break;
} }
$found_empty = true;
} }
return $num_lines; $cursor++;
}
return ($cursor - $start_cursor);
} }
public function markupText($text, $children) { public function markupText($text, $children) {

View file

@ -204,6 +204,7 @@ final class PhutilRemarkupEngine extends PhutilMarkupEngine {
} }
$cursor += $num_lines; $cursor += $num_lines;
break; break;
} }
} }

View file

@ -0,0 +1,5 @@
%%%xyz
~~~~~~~~~~
<p class="remarkup-literal">xyz</p>
~~~~~~~~~~
xyz