bug #38122 [HttpClient] Fix Array to string conversion notice when parsing JSON error body with non-scalar detail property (emarref)

This PR was squashed before being merged into the 4.4 branch.

Discussion
----------

[HttpClient] Fix Array to string conversion notice when parsing JSON error body with non-scalar detail property

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #38118
| License       | MIT
| Doc PR        | no

An earlier commit added the ability to detect common API formats and extract a useful error message from the error response payload. To achieve this, if a `title` and `detail` property are found in the error response, the response is considered to be in a known format (RFC 7807) and these values are concatenated to form a helpful error message.

However, when either `title` or `detail` property are present, but the document is not intended to follow the RFC semantics, if the properties are not scalar (e.g. if the detail property is an array of field validation violations) then the concatenation of the strings causes a notice to be raised.

This pull request checks that the `title` and `detail` properties are scalar before attempting to concatenate them. If they are not, no enhanced error message is provided.

Commits
-------

76fa884319 [HttpClient] Fix Array to string conversion notice when parsing JSON error body with non-scalar detail property
This commit is contained in:
Nicolas Grekas 2020-09-09 11:17:46 +02:00
commit 9bb80841ed
2 changed files with 16 additions and 11 deletions

View File

@ -60,7 +60,8 @@ trait HttpExceptionTrait
// see http://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors
$separator = isset($body['hydra:title'], $body['hydra:description']) ? "\n\n" : '';
$message = ($body['hydra:title'] ?? '').$separator.($body['hydra:description'] ?? '');
} elseif (isset($body['title']) || isset($body['detail'])) {
} elseif ((isset($body['title']) || isset($body['detail']))
&& (is_scalar($body['title'] ?? '') && is_scalar($body['detail'] ?? ''))) {
// see RFC 7807 and https://jsonapi.org/format/#error-objects
$separator = isset($body['title'], $body['detail']) ? "\n\n" : '';
$message = ($body['title'] ?? '').$separator.($body['detail'] ?? '');

View File

@ -22,15 +22,24 @@ class HttpExceptionTraitTest extends TestCase
{
public function provideParseError(): iterable
{
yield ['application/ld+json', '{"hydra:title": "An error occurred", "hydra:description": "Some details"}'];
yield ['application/problem+json', '{"title": "An error occurred", "detail": "Some details"}'];
yield ['application/vnd.api+json', '{"title": "An error occurred", "detail": "Some details"}'];
$errorWithoutMessage = 'HTTP/1.1 400 Bad Request returned for "http://example.com".';
$errorWithMessage = <<<ERROR
An error occurred
Some details
ERROR;
yield ['application/ld+json', '{"hydra:title": "An error occurred", "hydra:description": "Some details"}', $errorWithMessage];
yield ['application/problem+json', '{"title": "An error occurred", "detail": "Some details"}', $errorWithMessage];
yield ['application/vnd.api+json', '{"title": "An error occurred", "detail": "Some details"}', $errorWithMessage];
yield ['application/json', '{"title": "An error occurred", "detail": {"field_name": ["Some details"]}}', $errorWithoutMessage];
}
/**
* @dataProvider provideParseError
*/
public function testParseError(string $mimeType, string $json): void
public function testParseError(string $mimeType, string $json, string $expectedMessage): void
{
$response = $this->createMock(ResponseInterface::class);
$response
@ -47,12 +56,7 @@ class HttpExceptionTraitTest extends TestCase
$e = new TestException($response);
$this->assertSame(400, $e->getCode());
$this->assertSame(<<<ERROR
An error occurred
Some details
ERROR
, $e->getMessage());
$this->assertSame($expectedMessage, $e->getMessage());
}
}