Add safeguard against infinite routing loops

This commit is contained in:
PJ Dietz 2013-08-16 17:49:37 -04:00
parent 6013198436
commit d91ac12541
2 changed files with 38 additions and 6 deletions

View File

@ -1,3 +1,9 @@
### v1.3.0
- Allow Routers to dispatch additional Routers.
### v1.2.2
- Fix issue with 100 Continue status codes, etc. where r\n\r\n appears within the list of headers
### v1.2.1
- Allow Request to read request headers without apache_request_headers().

View File

@ -10,7 +10,6 @@
namespace pjdietz\WellRESTed;
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Interfaces\RouteInterface;
@ -26,8 +25,14 @@ class Router extends RouteTarget implements RouterInterface
{
/** @var string Fully qualified name for the interface for handlers */
const ROUTE_TARGET_INTERFACE = '\\pjdietz\\WellRESTed\\Interfaces\\RouteTargetInterface';
/** @var int Default maximum number of levels of routing. */
const MAX_DEPTH = 10;
/** @var int maximum levels of routing before the router raises an error. */
protected $maxDepth = self::MAX_DEPTH;
/** @var array Array of Route objects */
private $routes;
/** @var int counter incrememted each time a router dispatches a route target. */
private $depth = 0;
/** Create a new Router. */
public function __construct()
@ -53,10 +58,16 @@ class Router extends RouteTarget implements RouterInterface
*/
public function getResponse(RequestInterface $request = null)
{
if (is_null($request)) {
$request = Request::getRequest();
// Set the instance's request, if the called passed one.
if (!is_null($request)) {
$this->request = $request;
}
// If the instance does not have a request, use the singleton.
if (is_null($this->request)) {
$this->request = Request::getRequest();
}
// Reference the request and path.
$request = $this->request;
$path = $request->getPath();
foreach ($this->routes as $route) {
@ -79,8 +90,10 @@ class Router extends RouteTarget implements RouterInterface
// If this instance already had a top-level router, pass it along.
// Otherwise, pass itself as the top-level router.
if (isset($this->router)) {
$this->router->incrementDepth();
$target->setRouter($this->router);
} else {
$this->incrementDepth();
$target->setRouter($this);
}
@ -95,6 +108,19 @@ class Router extends RouteTarget implements RouterInterface
return $this->getNoRouteResponse($request);
}
public function incrementDepth()
{
$this->depth++;
if ($this->depth >= $this->maxDepth) {
$response = $this->getInternalServerErrorResponse(
$this->getRequest(),
'Maximum recursion level reached.'
);
$response->respond();
exit;
}
}
/**
* Prepare a resonse indicating a 404 Not Found error
*
@ -109,10 +135,10 @@ class Router extends RouteTarget implements RouterInterface
}
/** Prepare a response indicating a 500 Internal Server Error */
protected function getInternalServerErrorResponse(RequestInterface $request)
protected function getInternalServerErrorResponse(RequestInterface $request, $message = '')
{
$response = new Response(500);
$response->body = 'Server error at ' . $request->getPath();
$response->setBody('Server error at ' . $request->getPath() . "\n" . $message);
return $response;
}