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:
parent
b2cfcda114
commit
6f09edeb91
3 changed files with 58 additions and 34 deletions
|
@ -22,51 +22,69 @@ final class PhutilRemarkupLiteralBlockRule extends PhutilRemarkupBlockRule {
|
|||
// output text and assists automated escaping of blocks coming into the
|
||||
// system.
|
||||
|
||||
$num_lines = 0;
|
||||
while (preg_match('/^\s*%%%/', $lines[$cursor])) {
|
||||
$num_lines++;
|
||||
$start_pattern = '(^\s*%%%)';
|
||||
$end_pattern = '(%%%\s*$)';
|
||||
$trivial_pattern = '(^\s*%%%\s*$)';
|
||||
|
||||
// If the line has ONLY "%%%", the block opener doesn't get to double
|
||||
// up as a block terminator.
|
||||
if (preg_match('/^\s*%%%\s*\z/', $lines[$cursor])) {
|
||||
$num_lines++;
|
||||
$cursor++;
|
||||
if (!preg_match($start_pattern, $lines[$cursor])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (isset($lines[$cursor])) {
|
||||
if (!preg_match('/%%%\s*$/', $lines[$cursor])) {
|
||||
$num_lines++;
|
||||
$cursor++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$cursor++;
|
||||
$start_cursor = $cursor;
|
||||
|
||||
$found_empty = false;
|
||||
while (isset($lines[$cursor])) {
|
||||
if (!strlen(trim($lines[$cursor]))) {
|
||||
$num_lines++;
|
||||
$block_start = null;
|
||||
while (true) {
|
||||
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++;
|
||||
$found_empty = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($found_empty) {
|
||||
// If there's an empty line after the block, stop merging blocks.
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($lines[$cursor])) {
|
||||
// If we're at the end of the input, stop looking for more lines.
|
||||
if ($block_start === null) {
|
||||
if (strlen(trim($line))) {
|
||||
break;
|
||||
}
|
||||
$found_empty = true;
|
||||
}
|
||||
|
||||
return $num_lines;
|
||||
$cursor++;
|
||||
}
|
||||
|
||||
return ($cursor - $start_cursor);
|
||||
}
|
||||
|
||||
public function markupText($text, $children) {
|
||||
|
|
|
@ -204,6 +204,7 @@ final class PhutilRemarkupEngine extends PhutilMarkupEngine {
|
|||
}
|
||||
|
||||
$cursor += $num_lines;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
%%%xyz
|
||||
~~~~~~~~~~
|
||||
<p class="remarkup-literal">xyz</p>
|
||||
~~~~~~~~~~
|
||||
xyz
|
Loading…
Reference in a new issue