Merge pull request #2730 from Icinga/bugfix/invalid-icinga-2-api-response-2728
Handle invalid Icinga 2 API response types
This commit is contained in:
commit
d2341369a9
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Exception\Json;
|
||||
|
||||
/**
|
||||
* Exception thrown by {@link \Icinga\Util\Json::decode()} on failure
|
||||
*/
|
||||
class JsonDecodeException extends JsonException
|
||||
{
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Exception\Json;
|
||||
|
||||
/**
|
||||
* Exception thrown by {@link \Icinga\Util\Json::encode()} on failure
|
||||
*/
|
||||
class JsonEncodeException extends JsonException
|
||||
{
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Exception\Json;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Exception thrown by {@link \Icinga\Util\Json} on failure
|
||||
*/
|
||||
abstract class JsonException extends IcingaException
|
||||
{
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||
|
||||
namespace Icinga\Util;
|
||||
|
||||
use Icinga\Exception\Json\JsonDecodeException;
|
||||
use Icinga\Exception\Json\JsonEncodeException;
|
||||
|
||||
/**
|
||||
* Wrap {@link json_encode()} and {@link json_decode()} with error handling
|
||||
*/
|
||||
class Json
|
||||
{
|
||||
/**
|
||||
* {@link json_encode()} wrapper
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $options
|
||||
* @param int $depth
|
||||
*
|
||||
* @return string
|
||||
* @throws JsonEncodeException
|
||||
*/
|
||||
public static function encode($value, $options = 0, $depth = 512)
|
||||
{
|
||||
$encoded = json_encode($value, $options, $depth);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new JsonEncodeException('%s: %s', static::lastErrorMsg(), var_export($value, true));
|
||||
}
|
||||
return $encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link json_decode()} wrapper
|
||||
*
|
||||
* @param string $json
|
||||
* @param bool $assoc
|
||||
* @param int $depth
|
||||
* @param int $options
|
||||
*
|
||||
* @return mixed
|
||||
* @throws JsonDecodeException
|
||||
*/
|
||||
public static function decode($json, $assoc = false, $depth = 512, $options = 0)
|
||||
{
|
||||
$decoded = json_decode($json, $assoc, $depth, $options);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new JsonDecodeException('%s: %s', static::lastErrorMsg(), var_export($json, true));
|
||||
}
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link json_last_error_msg()} replacement for PHP < 5.5.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function lastErrorMsg()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
return json_last_error_msg();
|
||||
}
|
||||
|
||||
// All possible error codes before PHP 5.5.0 (except JSON_ERROR_NONE)
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
return 'Maximum stack depth exceeded';
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
return 'State mismatch (invalid or malformed JSON)';
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
return 'Control character error, possibly incorrectly encoded';
|
||||
case JSON_ERROR_SYNTAX:
|
||||
return 'Syntax error';
|
||||
case JSON_ERROR_UTF8:
|
||||
return 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
default:
|
||||
return 'Unknown error';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
namespace Icinga\Module\Monitoring\Command\Transport;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Exception\Json\JsonDecodeException;
|
||||
use Icinga\Module\Monitoring\Command\IcingaApiCommand;
|
||||
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||
use Icinga\Module\Monitoring\Command\Renderer\IcingaApiCommandRenderer;
|
||||
|
@ -193,12 +194,18 @@ class ApiCommandTransport implements CommandTransportInterface
|
|||
$this->getHost(),
|
||||
$this->getPort()
|
||||
);
|
||||
$response = RestRequest::post($this->getUriFor($command->getEndpoint()))
|
||||
->authenticateWith($this->getUsername(), $this->getPassword())
|
||||
->sendJson()
|
||||
->noStrictSsl()
|
||||
->setPayload($command->getData())
|
||||
->send();
|
||||
|
||||
try {
|
||||
$response = RestRequest::post($this->getUriFor($command->getEndpoint()))
|
||||
->authenticateWith($this->getUsername(), $this->getPassword())
|
||||
->sendJson()
|
||||
->noStrictSsl()
|
||||
->setPayload($command->getData())
|
||||
->send();
|
||||
} catch (JsonDecodeException $e) {
|
||||
throw new CommandTransportException('Got invalid JSON response from the Icinga 2 API: %s', $e->getMessage());
|
||||
}
|
||||
|
||||
if (isset($response['error'])) {
|
||||
throw new CommandTransportException(
|
||||
'Can\'t send external Icinga command: %u %s',
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Icinga\Module\Monitoring\Web\Rest;
|
|||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Util\Json;
|
||||
|
||||
/**
|
||||
* REST Request
|
||||
|
@ -261,35 +262,6 @@ class RestRequest
|
|||
fclose($stream);
|
||||
}
|
||||
|
||||
$response = @json_decode($result, true);
|
||||
|
||||
if ($response === null) {
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
|
||||
throw new Exception(json_last_error_msg());
|
||||
} else {
|
||||
switch (json_last_error()) {
|
||||
case JSON_ERROR_DEPTH:
|
||||
$msg = 'The maximum stack depth has been exceeded';
|
||||
break;
|
||||
case JSON_ERROR_CTRL_CHAR:
|
||||
$msg = 'Control character error, possibly incorrectly encoded';
|
||||
break;
|
||||
case JSON_ERROR_STATE_MISMATCH:
|
||||
$msg = 'Invalid or malformed JSON';
|
||||
break;
|
||||
case JSON_ERROR_SYNTAX:
|
||||
$msg = 'Syntax error';
|
||||
break;
|
||||
case JSON_ERROR_UTF8:
|
||||
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
|
||||
break;
|
||||
default:
|
||||
$msg = 'An error occured when parsing a JSON string';
|
||||
}
|
||||
throw new Exception($msg);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
return Json::decode($result, true);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue