Skip to content

Commit

Permalink
properly handle escaping of children
Browse files Browse the repository at this point in the history
  • Loading branch information
withinboredom committed Oct 29, 2023
1 parent ec3b0c0 commit 2f49185
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .idea/php.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 22 additions & 5 deletions src/Template/Parser/StreamingCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ private function renderCharacterReference($document): Document

private function escapeData(int $selectionStart, Document $document): Closure
{
if($this->blockAttributes) {
return static fn(Closure $x) => $x($document);
}
$end = $document->mark() - 1;
$originalData = substr($document->code, $selectionStart, $end - $selectionStart);
$data = $this->blobber->replaceBlobs($originalData, $this->escaper->escapeHtml(...));
Expand Down Expand Up @@ -429,12 +432,18 @@ private function renderOpenTagName(Document $document): Document
case 'title':
case 'textarea':
$this->mustMatch = $tag;
if($this->blockAttributes) {
return $this->renderRCData($document);
}
$now = $document->mark();
return $this->renderRCData($document)
->snip($now, $this->lastTagCloseOpen, $output)
->insert($this->blobber->replaceBlobs($output, $this->escaper->escapeHtml(...)), $now);
case 'style':
$this->mustMatch = $tag;
if($this->blockAttributes) {
return $this->renderRawText($document);
}
$now = $document->mark();
return $this
->renderRawText($document)
Expand All @@ -447,12 +456,18 @@ private function renderOpenTagName(Document $document): Document
case 'plaintext':
case 'noframes':
$this->mustMatch = $tag;
if($this->blockAttributes) {
return $this->renderRawText($document);
}
$now = $document->mark();
return $this->renderRawText($document)
->snip($now, $this->lastTagCloseOpen, $output)
->insert($this->blobber->replaceBlobs($output, $this->escaper->escapeHtml(...)), $now);
case 'script':
$this->mustMatch = $tag;
if($this->blockAttributes) {
return $this->renderScriptData($document);
}
$now = $document->mark();
return $this
->renderScriptData($document)
Expand Down Expand Up @@ -1180,13 +1195,15 @@ private function renderAfterAttributeValueQuoted(Document $document): Document

private function processAttributes(Document $document): Document
{
$value = $this->blobber->replaceBlobs(
$this->attributeValue,
$this->escaper->escapeHtmlAttr(...)
);
if($this->blockAttributes) {
return $document;
}

$originalValue = $this->blobber->replaceBlobs($this->attributeValue, fn($_) => $_);
$value = $this->escaper->escapeHtmlAttr($originalValue);
// escaper doesn't escape single quotes, so we do that here.
$value = str_replace("'", ''', $value);
$this->setAttribute($this->attributeName, $value);
$this->setAttribute($this->attributeName, $originalValue);
if ($value !== $this->attributeValue) {
// we need to update the rendered html too...
$here = $document->mark();
Expand Down
75 changes: 75 additions & 0 deletions tests/StreamingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,78 @@ public function render(): string
)->getHeader('Set-Cookie')[0]
)->toStartWith('csrf_token=');
});

test('data providers do not escape their children', function () {
$container = containerWithComponents([
'provider' => new class implements \Bottledcode\SwytchFramework\Template\Functional\DataProvider {

public function provideAttributes(): array
{
return ['test' => 'test'];
}

public function provideValues(string $value): mixed
{
return $value;
}

public function render(string $test = ''): string
{
if ($test) {
return 'oh no';
}
return '<children></children>';
}
},
'echo' => new class {
public function render(string $test = ''): string
{
return $test;
}
},
'empty' => new class {
public function render()
{
return '';
}
}
]);
$streamer = $container->get(StreamingCompiler::class);
$document = <<<HTML
<provider><empty /></provider>
<provider>
<echo test="overridden" />
</provider>
<echo test="not overridden" />
HTML;

$result = $streamer->compile($document);
expect($result)->toMatchHtmlSnapshot();
});

it('passes variables correctly', function () {
$container = containerWithComponents([
'echo' => new class {
public function render(string $test = ''): string
{
return $test;
}
},
'child' => new class {
public function render(string $test = ''): string
{
return "<div>{{$test}}<children/></div>";
}
}
]);

$streamer = $container->get(StreamingCompiler::class);
$document = <<<HTML
<echo test="{some text}" />
<child test="{outer text}">
<echo test="{inner text}" />
</child>
HTML;
$result = $streamer->compile($document);
expect($result)->toMatchHtmlSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<html><body><p>test

not overridden

</p></body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html><body>
<p>some text
</p>
<div>outer text
inner text
</div>

</body></html>

0 comments on commit 2f49185

Please sign in to comment.