Merge pull request #53740 from nextcloud/fix/properly-fail-on-invalid-json

Properly fail on invalid json
This commit is contained in:
Andy Scherzinger 2025-07-03 18:00:28 +02:00 committed by GitHub
commit 0c087ece4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 34 additions and 6 deletions

View file

@ -987,6 +987,7 @@ class OC {
}
$request = Server::get(IRequest::class);
$request->throwDecodingExceptionIfAny();
$requestPath = $request->getRawPathInfo();
if ($requestPath === '/heartbeat') {
return;

View file

@ -45,7 +45,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
public const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost|\[::1\])$/';
protected string $inputStream;
protected $content;
private bool $isPutStreamContentAlreadySent = false;
protected array $items = [];
protected array $allowedKeys = [
'get',
@ -64,6 +64,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
protected ?CsrfTokenManager $csrfTokenManager;
protected bool $contentDecoded = false;
private ?\JsonException $decodingException = null;
/**
* @param array $vars An associative array with the following optional values:
@ -356,13 +357,13 @@ class Request implements \ArrayAccess, \Countable, IRequest {
protected function getContent() {
// If the content can't be parsed into an array then return a stream resource.
if ($this->isPutStreamContent()) {
if ($this->content === false) {
if ($this->isPutStreamContentAlreadySent) {
throw new \LogicException(
'"put" can only be accessed once if not '
. 'application/x-www-form-urlencoded or application/json.'
);
}
$this->content = false;
$this->isPutStreamContentAlreadySent = true;
return fopen($this->inputStream, 'rb');
} else {
$this->decodeContent();
@ -389,7 +390,14 @@ class Request implements \ArrayAccess, \Countable, IRequest {
// 'application/json' and other JSON-related content types must be decoded manually.
if (preg_match(self::JSON_CONTENT_TYPE_REGEX, $this->getHeader('Content-Type')) === 1) {
$params = json_decode(file_get_contents($this->inputStream), true);
$content = file_get_contents($this->inputStream);
if ($content !== '') {
try {
$params = json_decode($content, true, flags:JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
$this->decodingException = $e;
}
}
if (\is_array($params) && \count($params) > 0) {
$this->items['params'] = $params;
if ($this->method === 'POST') {
@ -413,6 +421,12 @@ class Request implements \ArrayAccess, \Countable, IRequest {
$this->contentDecoded = true;
}
public function throwDecodingExceptionIfAny(): void {
if ($this->decodingException !== null) {
throw $this->decodingException;
}
}
/**
* Checks if the CSRF check was correct

View file

@ -305,4 +305,14 @@ interface IRequest {
* @since 8.1.0
*/
public function getServerHost(): string;
/**
* If decoding the request content failed, throw an exception.
* Currently only \JsonException for json decoding errors,
* but in the future may throw other exceptions for other decoding issues.
*
* @throws \Exception
* @since 32.0.0
*/
public function throwDecodingExceptionIfAny(): void;
}

View file

@ -50,11 +50,14 @@ try {
// side effects in existing apps
OC_App::loadApps();
$request = Server::get(IRequest::class);
$request->throwDecodingExceptionIfAny();
if (!Server::get(IUserSession::class)->isLoggedIn()) {
OC::handleLogin(Server::get(IRequest::class));
OC::handleLogin($request);
}
Server::get(Router::class)->match('/ocsapp' . Server::get(IRequest::class)->getRawPathInfo());
Server::get(Router::class)->match('/ocsapp' . $request->getRawPathInfo());
} catch (MaxDelayReached $ex) {
ApiHelper::respond(Http::STATUS_TOO_MANY_REQUESTS, $ex->getMessage());
} catch (ResourceNotFoundException $e) {