From a6bef5eacd40ef98312c679f6159f9800ddc2785 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 23 Jul 2019 18:13:24 -0400 Subject: [PATCH] Allow disabling debug content in debug mode (preview mode) --- .../ErrorRenderer/HtmlErrorRenderer.php | 3 +- .../ErrorRenderer/JsonErrorRenderer.php | 4 +- .../ErrorRenderer/TxtErrorRenderer.php | 3 +- .../ErrorRenderer/XmlErrorRenderer.php | 3 +- .../ErrorRenderer/HtmlErrorRendererTest.php | 52 +++++++++++++++-- .../ErrorRenderer/JsonErrorRendererTest.php | 49 ++++++++++++++-- .../ErrorRenderer/TxtErrorRendererTest.php | 50 +++++++++++++++-- .../ErrorRenderer/XmlErrorRendererTest.php | 56 +++++++++++++++++-- 8 files changed, 199 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php index 59d8504d41..f2aee487f7 100644 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/HtmlErrorRenderer.php @@ -91,10 +91,11 @@ class HtmlErrorRenderer implements ErrorRendererInterface private function renderException(FlattenException $exception, string $debugTemplate = 'views/exception_full.html.php'): string { + $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); $statusText = $this->escape($exception->getTitle()); $statusCode = $this->escape($exception->getStatusCode()); - if (!$this->debug) { + if (!$debug) { return $this->include('views/error.html.php', [ 'statusText' => $statusText, 'statusCode' => $statusCode, diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php index 689bdafeb7..52bc37f833 100644 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php +++ b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/JsonErrorRenderer.php @@ -38,12 +38,14 @@ class JsonErrorRenderer implements ErrorRendererInterface */ public function render(FlattenException $exception): string { + $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); + $content = [ 'title' => $exception->getTitle(), 'status' => $exception->getStatusCode(), 'detail' => $exception->getMessage(), ]; - if ($this->debug) { + if ($debug) { $content['exceptions'] = $exception->toArray(); } diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php index 80813aef85..e44d2a4a58 100644 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php +++ b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/TxtErrorRenderer.php @@ -38,11 +38,12 @@ class TxtErrorRenderer implements ErrorRendererInterface */ public function render(FlattenException $exception): string { + $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); $content = sprintf("[title] %s\n", $exception->getTitle()); $content .= sprintf("[status] %s\n", $exception->getStatusCode()); $content .= sprintf("[detail] %s\n", $exception->getMessage()); - if ($this->debug) { + if ($debug) { foreach ($exception->toArray() as $i => $e) { $content .= sprintf("[%d] %s: %s\n", $i + 1, $e['class'], $e['message']); foreach ($e['trace'] as $trace) { diff --git a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php index 3a132110dc..7a79bba857 100644 --- a/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php +++ b/src/Symfony/Component/ErrorRenderer/ErrorRenderer/XmlErrorRenderer.php @@ -40,13 +40,14 @@ class XmlErrorRenderer implements ErrorRendererInterface */ public function render(FlattenException $exception): string { + $debug = $this->debug && ($exception->getHeaders()['X-Debug'] ?? true); $title = $this->escapeXml($exception->getTitle()); $message = $this->escapeXml($exception->getMessage()); $statusCode = $this->escapeXml($exception->getStatusCode()); $charset = $this->escapeXml($this->charset); $exceptions = ''; - if ($this->debug) { + if ($debug) { $exceptions .= ''; foreach ($exception->toArray() as $e) { $exceptions .= sprintf('', $e['class'], $this->escapeXml($e['message'])); diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php index e1c55d3957..308733c025 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php +++ b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/HtmlErrorRendererTest.php @@ -12,16 +12,60 @@ namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\ErrorRenderer\ErrorRenderer\HtmlErrorRenderer; use Symfony\Component\ErrorRenderer\Exception\FlattenException; class HtmlErrorRendererTest extends TestCase { - public function testRender() + /** + * @dataProvider getRenderData + */ + public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) { - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $expected = '%A%A%AFoo (500 Internal Server Error)%A'; + $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); + } - $this->assertStringMatchesFormat($expected, (new HtmlErrorRenderer(true))->render($exception)); + public function getRenderData() + { + $expectedDebug = << + + +%AFoo (500 Internal Server Error) +%A
%A + +HTML; + + $expectedNonDebug = << + +%AAn Error Occurred: Internal Server Error +%A

The server returned a "500 Internal Server Error".

%A +HTML; + + yield '->render() returns the HTML content WITH stack traces in debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new HtmlErrorRenderer(true), + $expectedDebug, + ]; + + yield '->render() returns the HTML content WITHOUT stack traces in non-debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new HtmlErrorRenderer(false), + $expectedNonDebug, + ]; + + yield '->render() returns the HTML content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), + new HtmlErrorRenderer(true), + $expectedNonDebug, + ]; + + yield '->render() returns the HTML content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), + new HtmlErrorRenderer(false), + $expectedNonDebug, + ]; } } diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php index b9eeac2eeb..e35d3666db 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php +++ b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/JsonErrorRendererTest.php @@ -12,15 +12,23 @@ namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\ErrorRenderer\ErrorRenderer\JsonErrorRenderer; use Symfony\Component\ErrorRenderer\Exception\FlattenException; class JsonErrorRendererTest extends TestCase { - public function testRender() + /** + * @dataProvider getRenderData + */ + public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) { - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $expected = <<assertStringMatchesFormat($expected, $errorRenderer->render($exception)); + } + + public function getRenderData() + { + $expectedDebug = <<assertStringStartsWith($expected, (new JsonErrorRenderer(true))->render($exception)); + $expectedNonDebug = <<render() returns the JSON content WITH stack traces in debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new JsonErrorRenderer(true), + $expectedDebug, + ]; + + yield '->render() returns the JSON content WITHOUT stack traces in non-debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new JsonErrorRenderer(false), + $expectedNonDebug, + ]; + + yield '->render() returns the JSON content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), + new JsonErrorRenderer(true), + $expectedNonDebug, + ]; + + yield '->render() returns the JSON content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), + new JsonErrorRenderer(false), + $expectedNonDebug, + ]; } } diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php index 6a7b3fb9f7..afda69ad79 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php +++ b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/TxtErrorRendererTest.php @@ -12,16 +12,58 @@ namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\ErrorRenderer\ErrorRenderer\TxtErrorRenderer; use Symfony\Component\ErrorRenderer\Exception\FlattenException; class TxtErrorRendererTest extends TestCase { - public function testRender() + /** + * @dataProvider getRenderData + */ + public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) { - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $expected = '[title] Internal Server Error%A[status] 500%A[detail] Foo%A[1] RuntimeException: Foo%A'; + $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); + } - $this->assertStringMatchesFormat($expected, (new TxtErrorRenderer(true))->render($exception)); + public function getRenderData() + { + $expectedDebug = <<render() returns the TXT content WITH stack traces in debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new TxtErrorRenderer(true), + $expectedDebug, + ]; + + yield '->render() returns the TXT content WITHOUT stack traces in non-debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new TxtErrorRenderer(false), + $expectedNonDebug, + ]; + + yield '->render() returns the TXT content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), + new TxtErrorRenderer(true), + $expectedNonDebug, + ]; + + yield '->render() returns the TXT content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), + new TxtErrorRenderer(false), + $expectedNonDebug, + ]; } } diff --git a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php index 4470343c6d..078d15bbee 100644 --- a/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php +++ b/src/Symfony/Component/ErrorRenderer/Tests/ErrorRenderer/XmlErrorRendererTest.php @@ -12,16 +12,64 @@ namespace Symfony\Component\ErrorRenderer\Tests\ErrorRenderer; use PHPUnit\Framework\TestCase; +use Symfony\Component\ErrorRenderer\ErrorRenderer\ErrorRendererInterface; use Symfony\Component\ErrorRenderer\ErrorRenderer\XmlErrorRenderer; use Symfony\Component\ErrorRenderer\Exception\FlattenException; class XmlErrorRendererTest extends TestCase { - public function testRender() + /** + * @dataProvider getRenderData + */ + public function testRender(FlattenException $exception, ErrorRendererInterface $errorRenderer, string $expected) { - $exception = FlattenException::createFromThrowable(new \RuntimeException('Foo')); - $expected = '%A%AInternal Server Error%A500%AFoo%A'; + $this->assertStringMatchesFormat($expected, $errorRenderer->render($exception)); + } - $this->assertStringMatchesFormat($expected, (new XmlErrorRenderer(true))->render($exception)); + public function getRenderData() + { + $expectedDebug = << + + Internal Server Error + 500 + Foo + %A + +XML; + + $expectedNonDebug = << + + Internal Server Error + 500 + Foo + + +XML; + + yield '->render() returns the XML content WITH stack traces in debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new XmlErrorRenderer(true), + $expectedDebug, + ]; + + yield '->render() returns the XML content WITHOUT stack traces in non-debug mode' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo')), + new XmlErrorRenderer(false), + $expectedNonDebug, + ]; + + yield '->render() returns the XML content WITHOUT stack traces in debug mode FORCING non-debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => false]), + new XmlErrorRenderer(true), + $expectedNonDebug, + ]; + + yield '->render() returns the XML content WITHOUT stack traces in non-debug mode EVEN FORCING debug via X-Debug header' => [ + FlattenException::createFromThrowable(new \RuntimeException('Foo'), null, ['X-Debug' => true]), + new XmlErrorRenderer(false), + $expectedNonDebug, + ]; } }