Skip to content

Commit

Permalink
Merge pull request #8153 from kenjis/fix-IncomingRequest-getJSON
Browse files Browse the repository at this point in the history
fix: Validation raises TypeError when invalid JSON comes
  • Loading branch information
kenjis authored Nov 18, 2023
2 parents 83e4b71 + d0bf4bc commit 7160f66
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 1 deletion.
13 changes: 13 additions & 0 deletions system/HTTP/Exceptions/HTTPException.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ public static function forInvalidNegotiationType(string $type)
return new static(lang('HTTP.invalidNegotiationType', [$type]));
}

/**
* Thrown in IncomingRequest when the json_decode() produces
* an error code other than JSON_ERROR_NONE.
*
* @param string $error The error message
*
* @return static
*/
public static function forInvalidJSON(?string $error = null)
{
return new static(lang('HTTP.invalidJSON', [$error]));
}

/**
* For Message
*
Expand Down
14 changes: 13 additions & 1 deletion system/HTTP/IncomingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -573,10 +573,22 @@ public function getVar($index = null, $filter = null, $flags = null)
* @see http://php.net/manual/en/function.json-decode.php
*
* @return array|bool|float|int|stdClass|null
*
* @throws HTTPException When the body is invalid as JSON.
*/
public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0)
{
return json_decode($this->body ?? '', $assoc, $depth, $options);
if ($this->body === null) {
return null;
}

$result = json_decode($this->body, $assoc, $depth, $options);

if (json_last_error() !== JSON_ERROR_NONE) {
throw HTTPException::forInvalidJSON(json_last_error_msg());
}

return $result;
}

/**
Expand Down
1 change: 1 addition & 0 deletions system/Language/en/HTTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

// IncomingRequest
'invalidNegotiationType' => '"{0}" is not a valid negotiation type. Must be one of: media, charset, encoding, language.',
'invalidJSON' => 'Failed to parse JSON string. Error: {0}',

// Message
'invalidHTTPProtocol' => 'Invalid HTTP Protocol Version: {0}',
Expand Down
27 changes: 27 additions & 0 deletions tests/system/HTTP/IncomingRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use CodeIgniter\Test\CIUnitTestCase;
use Config\App;
use InvalidArgumentException;
use JsonException;
use TypeError;

/**
Expand Down Expand Up @@ -528,6 +529,32 @@ public function testGetJSONReturnsNullFromNullBody(): void
$this->assertNull($request->getJSON());
}

public function testGetJSONWithInvalidJSONString(): void
{
$this->expectException(HTTPException::class);
$this->expectExceptionMessage('Failed to parse JSON string. Error: Syntax error');

$config = new App();
$config->baseURL = 'http://example.com/';
$json = 'Invalid JSON string';
$request = $this->createRequest($config, $json);

$request->getJSON();
}

public function testGetJSONWithJsonThrowOnErrorAndInvalidJSONString(): void
{
$this->expectException(JsonException::class);
$this->expectExceptionMessage('Syntax error');

$config = new App();
$config->baseURL = 'http://example.com/';
$json = 'Invalid JSON string';
$request = $this->createRequest($config, $json);

$request->getJSON(false, 512, JSON_THROW_ON_ERROR);
}

public function testCanGrabGetRawInput(): void
{
$rawstring = 'username=admin001&role=administrator&usepass=0';
Expand Down
20 changes: 20 additions & 0 deletions tests/system/Validation/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace CodeIgniter\Validation;

use CodeIgniter\HTTP\Exceptions\HTTPException;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\SiteURI;
use CodeIgniter\HTTP\UserAgent;
Expand Down Expand Up @@ -789,6 +790,25 @@ public function testJsonInput(): void
unset($_SERVER['CONTENT_TYPE']);
}

public function testJsonInputInvalid(): void
{
$this->expectException(HTTPException::class);
$this->expectExceptionMessage('Failed to parse JSON string. Error: Syntax error');

$config = new App();
$json = 'invalid';
$request = new IncomingRequest($config, new URI(), $json, new UserAgent());

Check failure on line 800 in tests/system/Validation/ValidationTest.php

View workflow job for this annotation

GitHub Actions / Psalm Analysis

UndefinedClass

tests/system/Validation/ValidationTest.php:800:53: UndefinedClass: Class, interface or enum named CodeIgniter\Validation\URI does not exist (see https://psalm.dev/019)
$request->setHeader('Content-Type', 'application/json');

$rules = [
'role' => 'if_exist|max_length[5]',
];
$this->validation
->withRequest($request->withMethod('POST'))
->setRules($rules)
->run();
}

/**
* @see https://github.com/codeigniter4/CodeIgniter4/issues/6466
*/
Expand Down
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.4.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ and Traditional rules validate data of non-string types.
Message Changes
***************

- Added ``HTTP.invalidJSON`` error message.

*******
Changes
*******
Expand Down

0 comments on commit 7160f66

Please sign in to comment.