mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Limit recursion depth by configurable
Fixes https://github.com/erusev/parsedown/issues/681
This commit is contained in:
parent
b9b75dbcea
commit
9eb6a02334
51
src/Configurables/RecursionLimiter.php
Normal file
51
src/Configurables/RecursionLimiter.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Erusev\Parsedown\Configurables;
|
||||
|
||||
use Erusev\Parsedown\Configurable;
|
||||
|
||||
final class RecursionLimiter implements Configurable
|
||||
{
|
||||
/** @var int */
|
||||
private $maxDepth;
|
||||
|
||||
/** @var int */
|
||||
private $currentDepth;
|
||||
|
||||
/**
|
||||
* @param int $maxDepth
|
||||
* @param int $currentDepth
|
||||
*/
|
||||
private function __construct($maxDepth, $currentDepth)
|
||||
{
|
||||
$this->maxDepth = $maxDepth;
|
||||
$this->currentDepth = $currentDepth;
|
||||
}
|
||||
|
||||
/** @return self */
|
||||
public static function initial()
|
||||
{
|
||||
return self::maxDepth(256);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $maxDepth
|
||||
* @return self
|
||||
*/
|
||||
public static function maxDepth($maxDepth)
|
||||
{
|
||||
return new self($maxDepth, 0);
|
||||
}
|
||||
|
||||
/** @return self */
|
||||
public function increment()
|
||||
{
|
||||
return new self($this->maxDepth, $this->currentDepth + 1);
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function isDepthExceeded()
|
||||
{
|
||||
return ($this->maxDepth < $this->currentDepth);
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ use Erusev\Parsedown\Components\Inlines\PlainText;
|
||||
use Erusev\Parsedown\Components\StateUpdatingBlock;
|
||||
use Erusev\Parsedown\Configurables\BlockTypes;
|
||||
use Erusev\Parsedown\Configurables\InlineTypes;
|
||||
use Erusev\Parsedown\Configurables\RecursionLimiter;
|
||||
use Erusev\Parsedown\Html\Renderable;
|
||||
use Erusev\Parsedown\Html\Renderables\Text;
|
||||
use Erusev\Parsedown\Parsing\Excerpt;
|
||||
@ -82,6 +83,14 @@ final class Parsedown
|
||||
*/
|
||||
public static function blocks(Lines $Lines, State $State)
|
||||
{
|
||||
$RecursionLimiter = $State->get(RecursionLimiter::class)->increment();
|
||||
|
||||
if ($RecursionLimiter->isDepthExceeded()) {
|
||||
$State = $State->setting(new BlockTypes([], []));
|
||||
}
|
||||
|
||||
$State = $State->setting($RecursionLimiter);
|
||||
|
||||
/** @var Block[] */
|
||||
$Blocks = [];
|
||||
/** @var Block|null */
|
||||
@ -180,6 +189,14 @@ final class Parsedown
|
||||
# standardize line breaks
|
||||
$text = \str_replace(["\r\n", "\r"], "\n", $text);
|
||||
|
||||
$RecursionLimiter = $State->get(RecursionLimiter::class)->increment();
|
||||
|
||||
if ($RecursionLimiter->isDepthExceeded()) {
|
||||
return [Plaintext::build(new Excerpt($text, 0), $State)];
|
||||
}
|
||||
|
||||
$State = $State->setting($RecursionLimiter);
|
||||
|
||||
/** @var Inline[] */
|
||||
$Inlines = [];
|
||||
|
||||
|
54
tests/src/Configurables/RecursionLimiterTest.php
Normal file
54
tests/src/Configurables/RecursionLimiterTest.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Erusev\Parsedown\Tests\Configurables;
|
||||
|
||||
use Erusev\Parsedown\Configurables\RecursionLimiter;
|
||||
use Erusev\Parsedown\Parsedown;
|
||||
use Erusev\Parsedown\State;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class RecursionLimiterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
* @throws \PHPUnit\Framework\ExpectationFailedException
|
||||
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
|
||||
*/
|
||||
public function testDepthLimit()
|
||||
{
|
||||
$State = new State([RecursionLimiter::maxDepth(3)]);
|
||||
|
||||
$Parsedown = new Parsedown($State);
|
||||
|
||||
$borderline = '>>> foo';
|
||||
$exceeded = '>>>> foo';
|
||||
$exceededByInline = '>>> fo*o*';
|
||||
|
||||
$this->assertSame(
|
||||
(
|
||||
\str_repeat("<blockquote>\n", 3)
|
||||
. '<p>foo</p>'
|
||||
. \str_repeat("\n</blockquote>", 3)
|
||||
),
|
||||
$Parsedown->text($borderline)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
(
|
||||
\str_repeat("<blockquote>\n", 3)
|
||||
. '<p>> foo</p>'
|
||||
. \str_repeat("\n</blockquote>", 3)
|
||||
),
|
||||
$Parsedown->text($exceeded)
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
(
|
||||
\str_repeat("<blockquote>\n", 3)
|
||||
. '<p>fo*o*</p>'
|
||||
. \str_repeat("\n</blockquote>", 3)
|
||||
),
|
||||
$Parsedown->text($exceededByInline)
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user