When there is an uncaught exception, Drupal 8 displays a simple dump of the exception.

Although the page is served as 'Content-Type' = 'text/plain', it contains HTML. It looks better to me when I change the code (in FinalExceptionSubscriber.php) to serve as 'text/html'. See attached images.

Setting to "Minor" as the message would never be shown in production. Nevertheless, when debugging it's tedious to try to read text that contains HTML tags.

I asked for help on Drupal Answers. @4k4 suggested that the problem was potentially related to #2853300: Standardize fatal error/exception handling: backtrace for all formats, not just HTML, and that the "obvious" fix of changing the content-type would revert that issue.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

AdamPS created an issue. See original summary.

AdamPS’s picture

Status: Active » Needs review
FileSize
846 bytes

This is the patch for the "obvious fix" that we probably don't want to apply. However it will be useful to see if this breaks any tests.

Status: Needs review » Needs work

The last submitted patch, 2: exception-html.2924860-2.patch, failed testing. View results

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Murz’s picture

Thanks for the patch, it's short and works well for fixing described problem! Why it is obvious fix and not right? Does it broke some other places?

AdamPS’s picture

@Murz well there are 274 broken tests:-)

I think the error should only be text/html if the original request was HTML. It needs to be 'text/plain' for JSON and similar. So the code should probably should be something like this:

$content_type = ($this->getFormat($event->getRequest()) == 'Html') ? 'text/html' : 'text/plain';
$response = new Response($content, 500, ['Content-Type' => $content_type]);

It's not my top priority to create a new patch here, but if you are willing to create a new patch then I will definitely review it.

Keenegan’s picture

Status: Needs work » Needs review
FileSize
967 bytes

Here is the patch based on #8

Status: Needs review » Needs work

The last submitted patch, 9: exception-html.2924860-9.patch, failed testing. View results

Keenegan’s picture

Only one fail now, but I think the test testBacktraceEscaping should change because of these two lines :

$request->setFormat('html', ['text/html']);
$this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8');
AdamPS’s picture

@Kng thanks for working on this issue. Yes I agree - and as a bonus that means this patch will then have a test so no need to write a new one.

Keenegan’s picture

Ok, so I just have to change the test in my patch ?
Here's the patch with the ExceptionHandlingTest.php fixed

Keenegan’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 13: exception-html.2924850-13.patch, failed testing. View results

AdamPS’s picture

@Kng yes you are going in the right direction. You might have to change the tests a bit more. Obviously each time we should verify that the original request in the test was HTML.

Keenegan’s picture

Status: Needs work » Needs review
FileSize
2.4 KB

Oh yeah, I forgot about the testExceptionEscaping method.
This should be better now

AdamPS’s picture

Status: Needs review » Reviewed & tested by the community

Looks good thanks @Kng

Keenegan’s picture

Thank you for the huge help @AdamPS

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 17: exception-html.2924850-17.patch, failed testing. View results

AdamPS’s picture

Status: Needs work » Reviewed & tested by the community

Test fail was random, unrelated.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/EventSubscriber/FinalExceptionSubscriber.php
@@ -123,9 +123,10 @@ public function onException(GetResponseForExceptionEvent $event) {
+    $content_type = $event->getRequest()->getRequestFormat() == 'html' ? 'text/html' : 'text/plain';
     $content = $this->t('The website encountered an unexpected error. Please try again later.');
     $content .= $message ? '</br></br>' . $message : '';
-    $response = new Response($content, 500, ['Content-Type' => 'text/plain']);
+    $response = new Response($content, 500, ['Content-Type' => $content_type]);

An alternate fix and one that keeps the page text plain is to change the <br> tags to "\n\n". HTML in the exception message is already escaped so this is the only HTML on the page. I prefer this fix because in a way text/plain is defence in depth if auto-escaping the exception messages breaks for some reason.

AdamPS’s picture

Status: Needs work » Reviewed & tested by the community

Thanks @alexpott for looking at this issue.

HTML in the exception message is already escaped

I don't follow you. Yes exactly, the exception message is HTML-escaped which means it looks right in 'text/html' and wrong in 'text/plain'. Furthermore the exception message contains various HTML tags. Please see the attached image of this issue.

Given that this page calls $message = new FormattableMarkup it clearly does return HTML. Setting the content type to 'text/html' does seem like the right fix.

The suggested fix to use "\n\n" does not solve the issue. Setting back to RTBC for maintainer response.

if auto-escaping the exception messages breaks for some reason.

Please can you outline a specific scenario? If the output is malformed in an edge case then it's not necessarily a problem - the output has been malformed in all cases for years now. Do you see a security risk somehow?

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

@AdamPS hmmm good point. I think my fear about not escaping exception messages is irrational. The message is constructed one of two ways
$message = new FormattableMarkup('%type: @message in %function (line %line of %file).', $error);
or
$message = new FormattableMarkup('%type: @message in %function (line %line of %file). <pre class="backtrace">@backtrace</pre>', $error);
In both instances there's nothing from $error that is not escaped and if FormattableMarkup we have bigger problems. Plus escaping on exceptions is tested in \Drupal\KernelTests\Core\Routing\ExceptionHandlingTest::testExceptionEscaping and \Drupal\KernelTests\Core\Routing\ExceptionHandlingTest::testBacktraceEscaping so that's good.

I've pondered if we should consider running $content through \Drupal\Component\Render\PlainTextOutput::renderFromHtml() when outputting text/plain but that runs the risk of unescaping things so let's not to that here.

Even though this is a bug fix I'm going to commit to 8.8.x just in case any of my assumptions about security prove incorrect. I'm very sure that there's no harm in making this change but as a minor fix there's no rush either.

Committed c7bfe49 and pushed to 8.8.x. Thanks!

  • alexpott committed c7bfe49 on 8.8.x
    Issue #2924860 by Kng, AdamPS: “Uncaught exception” page contains HTML...
AdamPS’s picture

Great thanks @alexpott. I agree there is no rush, 8.8 is good.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.