Skip to content

Commit

Permalink
[5.6] Handle more JSON errors gracefully when JSON_PARTIAL_OUTPUT_ON_…
Browse files Browse the repository at this point in the history
…ERROR is set

It's fairly common for stack traces to be circular, i.e. they can't be encoded as JSON without limiting the recursion depth somehow. PHP automatically does this if JSON_PARTIAL_OUTPUT_ON_ERROR is true, but we still considered it an error.

By treating JSON_ERROR_RECURSION as okay if JSON_PARTIAL_OUTPUT_ON_ERROR is set we prevent things from blowing up if the user uses a JSON-based exception handler.

Since exceptions thrown in exception handlers are generally a recipe for disaster I added JSON_ERROR_INF_OR_NAN to the list of "acceptable" errors too.
  • Loading branch information
Sam Stenvall committed Mar 6, 2018
1 parent 20e8419 commit ea5bf58
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
21 changes: 18 additions & 3 deletions src/Illuminate/Http/JsonResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,24 @@ public function setData($data = [])
*/
protected function hasValidJson($jsonError)
{
return $jsonError === JSON_ERROR_NONE ||
($jsonError === JSON_ERROR_UNSUPPORTED_TYPE &&
$this->hasEncodingOption(JSON_PARTIAL_OUTPUT_ON_ERROR));
// No error is obviously fine
if ($jsonError === JSON_ERROR_NONE) {
return true;
}

// If the JSON_PARTIAL_OUTPUT_ON_ERROR option is set, some additional errors are fine
// (see https://secure.php.net/manual/en/json.constants.php)
if ($this->hasEncodingOption(JSON_PARTIAL_OUTPUT_ON_ERROR)) {
$acceptableErrors = [
JSON_ERROR_RECURSION,
JSON_ERROR_INF_OR_NAN,
JSON_ERROR_UNSUPPORTED_TYPE,
];

return \in_array($jsonError, $acceptableErrors);
}

return false;
}

/**
Expand Down
23 changes: 23 additions & 0 deletions tests/Http/HttpJsonResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ public function testJsonErrorResourceWithPartialOutputOnError()
$this->assertInstanceOf('stdClass', $data);
$this->assertNull($data->resource);
}

public function testJsonErrorRecursionDetectedWithPartialOutputOnError()
{
$objectA = new \stdClass();
$objectB = new \stdClass();
$objectA->b = $objectB;
$objectB->a = $objectA;

$response = new \Illuminate\Http\JsonResponse($objectA, 200, [], JSON_PARTIAL_OUTPUT_ON_ERROR);
$data = $response->getData();

$this->assertNotNull($data);
}

public function testJsonErrorInfOrNanWithPartialOutputOnError()
{
$data = ['product' => NAN];

$response = new \Illuminate\Http\JsonResponse($data, 200, [], JSON_PARTIAL_OUTPUT_ON_ERROR);
$data = $response->getData();

$this->assertNotNull($data);
}
}

class JsonResponseTestJsonableObject implements Jsonable
Expand Down

0 comments on commit ea5bf58

Please sign in to comment.