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 ### v1.2.1
- Allow Request to read request headers without apache_request_headers(). - Allow Request to read request headers without apache_request_headers().

View File

@ -10,7 +10,6 @@
namespace pjdietz\WellRESTed; namespace pjdietz\WellRESTed;
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface; use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface; use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Interfaces\RouteInterface; 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 */ /** @var string Fully qualified name for the interface for handlers */
const ROUTE_TARGET_INTERFACE = '\\pjdietz\\WellRESTed\\Interfaces\\RouteTargetInterface'; 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 */ /** @var array Array of Route objects */
private $routes; private $routes;
/** @var int counter incrememted each time a router dispatches a route target. */
private $depth = 0;
/** Create a new Router. */ /** Create a new Router. */
public function __construct() public function __construct()
@ -53,10 +58,16 @@ class Router extends RouteTarget implements RouterInterface
*/ */
public function getResponse(RequestInterface $request = null) public function getResponse(RequestInterface $request = null)
{ {
if (is_null($request)) { // Set the instance's request, if the called passed one.
$request = Request::getRequest(); 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(); $path = $request->getPath();
foreach ($this->routes as $route) { 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. // If this instance already had a top-level router, pass it along.
// Otherwise, pass itself as the top-level router. // Otherwise, pass itself as the top-level router.
if (isset($this->router)) { if (isset($this->router)) {
$this->router->incrementDepth();
$target->setRouter($this->router); $target->setRouter($this->router);
} else { } else {
$this->incrementDepth();
$target->setRouter($this); $target->setRouter($this);
} }
@ -95,6 +108,19 @@ class Router extends RouteTarget implements RouterInterface
return $this->getNoRouteResponse($request); 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 * 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 */ /** 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 = new Response(500);
$response->body = 'Server error at ' . $request->getPath(); $response->setBody('Server error at ' . $request->getPath() . "\n" . $message);
return $response; return $response;
} }