Use a more sophisticated inheritance and interface structure for HTTP exceptions (#2881)

HttpExceptionInterface now identifies HTTP exceptions, BaseHttpExceptions supersedes
HttpException as new superclass for other more concrete Exceptions and HttpException
is now a generic class to create new HTTP exceptions on the fly.

resolves #2880
This commit is contained in:
Johannes Meyer 2017-07-05 06:26:58 +02:00 committed by GitHub
parent d208b48b72
commit 375920f761
7 changed files with 128 additions and 31 deletions

View File

@ -6,9 +6,7 @@ namespace Icinga\Controllers;
use Zend_Controller_Plugin_ErrorHandler;
use Icinga\Application\Icinga;
use Icinga\Application\Logger;
use Icinga\Exception\Http\HttpBadRequestException;
use Icinga\Exception\Http\HttpMethodNotAllowedException;
use Icinga\Exception\Http\HttpNotFoundException;
use Icinga\Exception\Http\HttpExceptionInterface;
use Icinga\Exception\MissingParameterException;
use Icinga\Security\SecurityException;
use Icinga\Web\Controller\ActionController;
@ -67,12 +65,11 @@ class ErrorController extends ActionController
break;
default:
switch (true) {
case $exception instanceof HttpMethodNotAllowedException:
$this->getResponse()->setHttpResponseCode(405);
$this->getResponse()->setHeader('Allow', $exception->getAllowedMethods());
break;
case $exception instanceof HttpNotFoundException:
$this->getResponse()->setHttpResponseCode(404);
case $exception instanceof HttpExceptionInterface:
$this->getResponse()->setHttpResponseCode($exception->getStatusCode());
foreach ($exception->getHeaders() as $name => $value) {
$this->getResponse()->setHeader($name, $value, true);
}
break;
case $exception instanceof MissingParameterException:
$this->getResponse()->setHttpResponseCode(400);
@ -81,9 +78,6 @@ class ErrorController extends ActionController
'Missing parameter ' . $exception->getParameter()
);
break;
case $exception instanceof HttpBadRequestException:
$this->getResponse()->setHttpResponseCode(400);
break;
case $exception instanceof SecurityException:
$this->getResponse()->setHttpResponseCode(403);
break;

View File

@ -0,0 +1,74 @@
<?php
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
namespace Icinga\Exception\Http;
use Icinga\Exception\IcingaException;
/**
* Base class for HTTP exceptions
*/
class BaseHttpException extends IcingaException implements HttpExceptionInterface
{
/**
* This exception's HTTP status code
*
* @var int
*/
protected $statusCode;
/**
* This exception's HTTP response headers
*
* @var array
*/
protected $headers;
/**
* Return this exception's HTTP status code
*
* @return int
*/
public function getStatusCode()
{
return $this->statusCode;
}
/**
* Set this exception's HTTP response headers
*
* @param array $headers
*
* @return $this
*/
public function setHeaders(array $headers)
{
$this->headers = $headers;
return $this;
}
/**
* Set/Add a HTTP response header
*
* @param string $name
* @param string $value
*
* @return $this
*/
public function setHeader($name, $value)
{
$this->headers[$name] = $value;
return $this;
}
/**
* Return this exception's HTTP response headers
*
* @return array An array where each key is a header name and the value its value
*/
public function getHeaders()
{
return $this->headers;
}
}

View File

@ -6,7 +6,7 @@ namespace Icinga\Exception\Http;
/**
* Exception thrown for sending a HTTP 400 response w/ a custom message
*/
class HttpBadRequestException extends HttpException
class HttpBadRequestException extends BaseHttpException
{
protected $statusCode = 400;
}

View File

@ -3,12 +3,23 @@
namespace Icinga\Exception\Http;
use Icinga\Exception\IcingaException;
/**
* Base class for HTTP exceptions
*/
abstract class HttpException extends IcingaException
class HttpException extends BaseHttpException
{
/**
* Create a new HttpException
*
* @param int $statusCode HTTP status code
* @param string $message Exception message or exception format string
* @param mixed ...$arg Format string argument
*
* If there is at least one exception, the last one will be used for exception chaining.
*/
public function __construct($statusCode, $message)
{
$this->statusCode = (int) $statusCode;
$args = func_get_args();
array_shift($args);
call_user_func_array('parent::__construct', $args);
}
}

View File

@ -0,0 +1,22 @@
<?php
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
namespace Icinga\Exception\Http;
interface HttpExceptionInterface
{
/**
* Return this exception's HTTP status code
*
* @return int
*/
public function getStatusCode();
/**
* Return this exception's HTTP response headers
*
* @return array An array where each key is a header name and the value its value
*/
public function getHeaders();
}

View File

@ -6,14 +6,9 @@ namespace Icinga\Exception\Http;
/**
* Exception thrown if the HTTP method is not allowed
*/
class HttpMethodNotAllowedException extends HttpException
class HttpMethodNotAllowedException extends BaseHttpException
{
/**
* Allowed HTTP methods
*
* @var string
*/
protected $allowedMethods;
protected $statusCode = 405;
/**
* Get the allowed HTTP methods
@ -22,7 +17,8 @@ class HttpMethodNotAllowedException extends HttpException
*/
public function getAllowedMethods()
{
return $this->allowedMethods;
$headers = $this->getHeaders();
return isset($headers['Allow']) ? $headers['Allow'] : null;
}
/**
@ -34,7 +30,7 @@ class HttpMethodNotAllowedException extends HttpException
*/
public function setAllowedMethods($allowedMethods)
{
$this->allowedMethods = (string) $allowedMethods;
$this->setHeader('Allow', (string) $allowedMethods);
return $this;
}
}

View File

@ -6,7 +6,7 @@ namespace Icinga\Exception\Http;
/**
* Exception thrown for sending a HTTP 404 response w/ a custom message
*/
class HttpNotFoundException extends HttpException
class HttpNotFoundException extends BaseHttpException
{
protected $statusCode = 404;
}