Commit 49a7dfcb authored by alexpott's avatar alexpott

Issue #3042124 by gabesullice, Wim Leers, logickal, benjy, Grimreaper:...

Issue #3042124 by gabesullice, Wim Leers, logickal, benjy, Grimreaper: [regression] Empty response body when user is an administrator and an exception is thrown; some traces cannot be encoded because of recursion detection
parent f3216900
......@@ -132,42 +132,6 @@ public function denormalize($data, $class, $format = NULL, array $context = [])
return $data_internal;
}
/**
* Rasterizes a value recursively.
*
* This is mainly for configuration entities where a field can be a tree of
* values to rasterize.
*
* @param mixed $value
* Either a scalar, an array or a rasterizable object.
*
* @return mixed
* The rasterized value.
*/
protected static function rasterizeValueRecursive($value) {
if (!$value || is_scalar($value)) {
return $value;
}
if (is_array($value)) {
$output = [];
foreach ($value as $key => $item) {
$output[$key] = static::rasterizeValueRecursive($item);
}
return $output;
}
if ($value instanceof CacheableNormalization) {
return $value->getNormalization();
}
// If the object can be turned into a string it's better than nothing.
if (method_exists($value, '__toString')) {
return $value->__toString();
}
// We give up, since we do not know how to rasterize this.
return NULL;
}
/**
* Gets a field item instance for use with SerializedColumnNormalizerTrait.
*
......
......@@ -49,7 +49,7 @@ public function __construct(AccountInterface $current_user) {
* {@inheritdoc}
*/
public function normalize($object, $format = NULL, array $context = []) {
return new HttpExceptionNormalizerValue(new CacheableMetadata(), $this->buildErrorObjects($object));
return new HttpExceptionNormalizerValue(new CacheableMetadata(), static::rasterizeValueRecursive($this->buildErrorObjects($object)));
}
/**
......
......@@ -2,6 +2,7 @@
namespace Drupal\jsonapi\Normalizer;
use Drupal\jsonapi\Normalizer\Value\CacheableNormalization;
use Drupal\serialization\Normalizer\NormalizerBase as SerializationNormalizerBase;
/**
......@@ -20,6 +21,42 @@ abstract class NormalizerBase extends SerializationNormalizerBase {
*/
protected $format = 'api_json';
/**
* Rasterizes a value recursively.
*
* This is mainly for configuration entities where a field can be a tree of
* values to rasterize.
*
* @param mixed $value
* Either a scalar, an array or a rasterizable object.
*
* @return mixed
* The rasterized value.
*/
protected static function rasterizeValueRecursive($value) {
if (!$value || is_scalar($value)) {
return $value;
}
if (is_array($value)) {
$output = [];
foreach ($value as $key => $item) {
$output[$key] = static::rasterizeValueRecursive($item);
}
return $output;
}
if ($value instanceof CacheableNormalization) {
return $value->getNormalization();
}
// If the object can be turned into a string it's better than nothing.
if (method_exists($value, '__toString')) {
return $value->__toString();
}
// We give up, since we do not know how to rasterize this.
return NULL;
}
/**
* {@inheritdoc}
*/
......
......@@ -905,4 +905,52 @@ public function testMapFieldTypeNormalizationFromIssue3040590() {
$this->assertSame(['foo' => 'bar'], $data['data'][0]['attributes']['data']);
}
/**
* Tests that the response still has meaningful error messages.
*/
public function testRecursionDetectedWhenResponseContainsViolationsFrom3042124() {
$this->config('jsonapi.settings')->set('read_only', FALSE)->save(TRUE);
// Set up default request.
$url = Url::fromUri('internal:/jsonapi/node/article');
$request_options = [
RequestOptions::HEADERS => [
'Content-Type' => 'application/vnd.api+json',
'Accept' => 'application/vnd.api+json',
],
RequestOptions::JSON => [
'data' => [
'type' => 'node--article',
'attributes' => [],
],
],
];
// Set up test users.
$user = $this->drupalCreateUser(['bypass node access'], 'Sam');
$admin = $this->drupalCreateUser([], 'Gandalf', TRUE);
// Make request as regular user.
$request_options[RequestOptions::AUTH] = [$user->getUsername(), $user->pass_raw];
$this->request('POST', $url, $request_options);
$response = $this->request('POST', $url, $request_options);
// Assert that the response has a body.
$data = Json::decode((string) $response->getBody());
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
$this->assertSame(sprintf('title: This value should not be null.'), $data['errors'][0]['detail']);
// Make request as regular user.
$request_options[RequestOptions::AUTH] = [$admin->getUsername(), $admin->pass_raw];
$this->request('POST', $url, $request_options);
$response = $this->request('POST', $url, $request_options);
// Assert that the response has a body.
$data = Json::decode((string) $response->getBody());
$this->assertSame(422, $response->getStatusCode());
$this->assertNotNull($data);
$this->assertSame(sprintf('title: This value should not be null.'), $data['errors'][0]['detail']);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment