diff --git a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php index 4737e8031a4854e20de698f6512b9c027530b948..7b5ecc1280afea161487c4399d55c158b132c045 100644 --- a/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/DefaultExceptionSubscriber.php @@ -7,7 +7,6 @@ use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\Utility\Error; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; @@ -119,7 +118,7 @@ protected function onHtml(GetResponseForExceptionEvent $event) { $content = $this->t('The website encountered an unexpected error. Please try again later.'); $content .= $message ? '</br></br>' . $message : ''; - $response = new Response($content, 500); + $response = new Response($content, 500, ['Content-Type' => 'text/plain']); if ($exception instanceof HttpExceptionInterface) { $response->setStatusCode($exception->getStatusCode()); @@ -132,34 +131,6 @@ protected function onHtml(GetResponseForExceptionEvent $event) { $event->setResponse($response); } - /** - * Handles any exception as a generic error page for JSON. - * - * @todo This should probably check the error reporting level. - * - * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event - * The event to process. - */ - protected function onJson(GetResponseForExceptionEvent $event) { - $exception = $event->getException(); - $error = Error::decodeException($exception); - - // Display the message if the current error reporting level allows this type - // of message to be displayed, - $data = NULL; - if (error_displayable($error) && $message = $exception->getMessage()) { - $data = ['message' => sprintf('A fatal error occurred: %s', $message)]; - } - - $response = new JsonResponse($data, Response::HTTP_INTERNAL_SERVER_ERROR); - if ($exception instanceof HttpExceptionInterface) { - $response->setStatusCode($exception->getStatusCode()); - $response->headers->add($exception->getHeaders()); - } - - $event->setResponse($response); - } - /** * Handles an HttpExceptionInterface exception for unknown formats. * @@ -218,16 +189,6 @@ protected function getFormat(Request $request) { $format = 'json'; } - // Make an educated guess that any Accept header type that includes "json" - // can probably handle a generic JSON response for errors. As above, for - // any format this doesn't catch or that wants custom handling should - // register its own exception listener. - foreach ($request->getAcceptableContentTypes() as $mime) { - if (strpos($mime, 'html') === FALSE && strpos($mime, 'json') !== FALSE) { - $format = 'json'; - } - } - return $format; } diff --git a/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php index 76cc55ee3abcb573aa5c26dfbd605032d14bf27b..6ccb743356de49dc3c874a7e1ca707ae313a4f6b 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ExceptionJsonSubscriber.php @@ -14,7 +14,7 @@ class ExceptionJsonSubscriber extends HttpExceptionSubscriberBase { * {@inheritdoc} */ protected function getHandledFormats() { - return ['json']; + return ['json', 'drupal_modal', 'drupal_dialog', 'drupal_ajax']; } /** diff --git a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php index 9b9d13c5884935fe98448a7914b0ebd13b7ed7d6..c827450aeb089d598141d6e178de93fabd1dc205 100644 --- a/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php +++ b/core/modules/editor/src/Tests/QuickEditIntegrationLoadingTest.php @@ -89,12 +89,12 @@ public function testUsersWithoutPermission() { $response = $this->drupalPost('editor/' . 'node/1/body/en/full', '', array(), array('query' => array(MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax'))); $this->assertResponse(403); if (!$user->hasPermission('access in-place editing')) { - $message = "A fatal error occurred: The 'access in-place editing' permission is required."; - $this->assertIdentical(Json::encode(['message' => $message]), $response); + $message = "The 'access in-place editing' permission is required."; } else { - $this->assertIdentical('{}', $response); + $message = ''; } + $this->assertIdentical(Json::encode(['message' => $message]), $response); } } diff --git a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php index ab66227ad1ae3f09d15ae3aec220cb30caee5970..1570a27ad7d11d8ad00d2affef2929cc4eafa442 100644 --- a/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php +++ b/core/modules/quickedit/src/Tests/QuickEditLoadingTest.php @@ -115,12 +115,12 @@ public function testUserWithoutPermission() { $this->assertIdentical(Json::encode(['message' => "The 'access in-place editing' permission is required."]), $response); $this->assertResponse(403); - // Quick Edit's JavaScript would SearchRankingTestnever hit these endpoints if the metadata + // Quick Edit's JavaScript would never hit these endpoints if the metadata // was empty as above, but we need to make sure that malicious users aren't // able to use any of the other endpoints either. $post = array('editors[0]' => 'form') + $this->getAjaxPageStatePostData(); $response = $this->drupalPost('quickedit/attachments', '', $post, ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']]); - $message = Json::encode(['message' => "A fatal error occurred: The 'access in-place editing' permission is required."]); + $message = Json::encode(['message' => "The 'access in-place editing' permission is required."]); $this->assertIdentical($message, $response); $this->assertResponse(403); $post = array('nocssjs' => 'true') + $this->getAjaxPageStatePostData(); diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php index 63991311a90a6e86accac3a54900032c019c9049..b04da54373e8e6ebbe1cbf6ba2ce894a19bd6579 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/Comment/CommentResourceTestBase.php @@ -280,8 +280,8 @@ public function testPostDxWithoutCriticalBaseFields() { $response = $this->request('POST', $url, $request_options); // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364. $this->assertSame(500, $response->getStatusCode()); - $this->assertSame(['application/json'], $response->getHeader('Content-Type')); - $this->assertSame('{"message":"A fatal error occurred: Internal Server Error"}', (string) $response->getBody()); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertSame('Internal Server Error', (string) $response->getBody()); //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nentity_type: This value should not be null.\n", $response); // DX: 422 when missing 'entity_id' field. @@ -303,10 +303,9 @@ public function testPostDxWithoutCriticalBaseFields() { // DX: 422 when missing 'entity_type' field. $request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['field_name' => TRUE]), static::$format); $response = $this->request('POST', $url, $request_options); - // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364. + // @todo Uncomment, remove next 2 lines in https://www.drupal.org/node/2820364. $this->assertSame(500, $response->getStatusCode()); - $this->assertSame(['application/json'], $response->getHeader('Content-Type')); - $this->assertSame('{"message":"A fatal error occurred: Field is unknown."}', (string) $response->getBody()); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nfield_name: This value should not be null.\n", $response); } diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index 339af6ba162451dd888a9324540c67f46a809fc0..c7bcb97167074f49971464a25d36074a29308dc8 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -5,7 +5,6 @@ use Drupal\Component\Utility\NestedArray; use Drupal\Core\Cache\Cache; use Drupal\Core\Config\Entity\ConfigEntityInterface; -use Drupal\Core\Entity\EntityChangedInterface; use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Url; use Drupal\field\Entity\FieldConfig; @@ -487,17 +486,17 @@ public function testGet() { // DX: 406 when requesting unsupported format. $response = $this->request('GET', $url, $request_options); $this->assert406Response($response); - $this->assertNotSame([static::$mimeType], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); $request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType; - // DX: 406 when requesting unsupported format but specifying Accept header. - // @todo Update in https://www.drupal.org/node/2825347. + // DX: 406 when requesting unsupported format but specifying Accept header: + // should result in a text/plain response. $response = $this->request('GET', $url, $request_options); $this->assert406Response($response); - $this->assertSame(['application/json'], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); $url = Url::fromRoute('rest.entity.' . static::$entityTypeId . '.GET.' . static::$format); @@ -566,11 +565,11 @@ public function testPost() { $url->setOption('query', []); - // DX: 415 when no Content-Type request header, but HTML if canonical route. + // DX: 415 when no Content-Type request header, plain text if canonical URL. $response = $this->request('POST', $url, $request_options); if ($has_canonical_url) { $this->assertSame(415, $response->getStatusCode()); - $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); $this->assertContains(htmlspecialchars('No "Content-Type" request header specified'), (string) $response->getBody()); } else { @@ -728,12 +727,12 @@ public function testPatch() { $request_options = []; - // DX: 405 when resource not provisioned, but HTML if canonical route. + // DX: 404 when resource not provisioned, but 405 if canonical route. $response = $this->request('PATCH', $url, $request_options); if ($has_canonical_url) { $this->assertSame(405, $response->getStatusCode()); $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow')); - $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); } else { $this->assertResourceErrorResponse(404, 'No route found for "PATCH ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); @@ -758,7 +757,7 @@ public function testPatch() { $response = $this->request('PATCH', $url, $request_options); if ($has_canonical_url) { $this->assertSame(415, $response->getStatusCode()); - $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); $this->assertTrue(FALSE !== strpos((string) $response->getBody(), htmlspecialchars('No "Content-Type" request header specified'))); } else { @@ -922,12 +921,12 @@ public function testDelete() { $request_options = []; - // DX: 405 when resource not provisioned, but HTML if canonical route. + // DX: 404 when resource not provisioned, but 405 if canonical route. $response = $this->request('DELETE', $url, $request_options); if ($has_canonical_url) { $this->assertSame(405, $response->getStatusCode()); $this->assertSame(['GET, POST, HEAD'], $response->getHeader('Allow')); - $this->assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type')); + $this->assertSame(['text/plain; charset=UTF-8'], $response->getHeader('Content-Type')); } else { $this->assertResourceErrorResponse(404, 'No route found for "DELETE ' . str_replace($this->baseUrl, '', $this->getUrl()->setAbsolute()->toString()) . '"', $response); diff --git a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php index 85649484bb7f24d8d339237c24596a092bd8e895..f7e60746eab082369b92a47c1ac56052210b800f 100644 --- a/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php +++ b/core/tests/Drupal/KernelTests/Core/Routing/ExceptionHandlingTest.php @@ -155,7 +155,7 @@ public function testBacktraceEscaping() { $kernel = \Drupal::getContainer()->get('http_kernel'); $response = $kernel->handle($request)->prepare($request); $this->assertEqual($response->getStatusCode(), Response::HTTP_INTERNAL_SERVER_ERROR); - $this->assertEqual($response->headers->get('Content-type'), 'text/html; charset=UTF-8'); + $this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8'); // Test both that the backtrace is properly escaped, and that the unescaped // string is not output at all. @@ -178,7 +178,7 @@ public function testExceptionEscaping() { $kernel = \Drupal::getContainer()->get('http_kernel'); $response = $kernel->handle($request)->prepare($request); $this->assertEqual($response->getStatusCode(), Response::HTTP_INTERNAL_SERVER_ERROR); - $this->assertEqual($response->headers->get('Content-type'), 'text/html; charset=UTF-8'); + $this->assertEqual($response->headers->get('Content-type'), 'text/plain; charset=UTF-8'); // Test message is properly escaped, and that the unescaped string is not // output at all.