Skip to content

Commit

Permalink
Push host checking into Route.
Browse files Browse the repository at this point in the history
Add a `parseRequest` method to `Route` as well. This gives the 'new' API
a consistent implementation across all the routing layers. It also
provides a more flexible way for people to customize routing as they
have access to the entire request via the new API.
  • Loading branch information
markstory committed Jan 8, 2017
1 parent be56d53 commit 791cce6
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 11 deletions.
24 changes: 20 additions & 4 deletions src/Routing/Route/Route.php
Expand Up @@ -15,6 +15,7 @@
namespace Cake\Routing\Route;

use Cake\Http\ServerRequest;
use Psr\Http\Message\ServerRequestInterface;
use Cake\Routing\Router;

/**
Expand Down Expand Up @@ -281,6 +282,24 @@ public function getName()
return $this->_name = strtolower($name);
}

/**
* Checks to see if the given URL can be parsed by this route.
*
* If the route can be parsed an array of parameters will be returned; if not
* false will be returned.
*
* @param \Psr\Http\Message\ServerRequestInterface $request The URL to attempt to parse.
* @return array|false An array of request parameters, or false on failure.
*/
public function parseRequest(ServerRequestInterface $request)
{
$uri = $request->getUri();
if (isset($this->options['_host']) && !$this->hostMatches($uri->getHost())) {
return false;
}
return $this->parse($uri->getPath(), $request->getMethod());
}

/**
* Checks to see if the given URL can be parsed by this route.
*
Expand All @@ -290,6 +309,7 @@ public function getName()
* @param string $url The URL to attempt to parse.
* @param string $method The HTTP method of the request being parsed.
* @return array|false An array of request parameters, or false on failure.
* @deprecated 3.4.0 Use/implement parseRequest() instead as it provides more flexibility/control.
*/
public function parse($url, $method = '')
{
Expand Down Expand Up @@ -356,7 +376,6 @@ public function parse($url, $method = '')
}
}
}

$route['_matchedRoute'] = $this->template;

return $route;
Expand All @@ -370,9 +389,6 @@ public function parse($url, $method = '')
*/
public function hostMatches($host)
{
if (!isset($this->options['_host'])) {
return true;
}
$pattern = '@^' . str_replace('\*', '.*', preg_quote($this->options['_host'], '@')) . '$@';

return preg_match($pattern, $host) !== 0;
Expand Down
8 changes: 1 addition & 7 deletions src/Routing/RouteCollection.php
Expand Up @@ -158,21 +158,15 @@ public function parse($url, $method = '')
public function parseRequest(ServerRequestInterface $request)
{
$uri = $request->getUri();
$method = $request->getMethod();
$urlPath = $uri->getPath();
$host = $uri->getHost();
foreach (array_keys($this->_paths) as $path) {
if (strpos($urlPath, $path) !== 0) {
continue;
}

/* @var \Cake\Routing\Route\Route $route */
foreach ($this->_paths[$path] as $route) {
if (!$route->hostMatches($host)) {
continue;
}

$r = $route->parse($urlPath, $method);
$r = $route->parseRequest($request);
if ($r === false) {
continue;
}
Expand Down
74 changes: 74 additions & 0 deletions tests/TestCase/Routing/Route/RouteTest.php
Expand Up @@ -15,6 +15,7 @@
namespace Cake\Test\TestCase\Routing\Route;

use Cake\Core\Configure;
use Cake\Http\ServerRequest;
use Cake\Routing\Router;
use Cake\Routing\Route\Route;
use Cake\TestSuite\TestCase;
Expand Down Expand Up @@ -856,6 +857,79 @@ public function testQueryStringGeneration()
ini_set('arg_separator.output', $restore);
}

/**
* Ensure that parseRequest() calls parse() as that is required
* for backwards compat
*
* @return void
*/
public function testParseRequestDelegates()
{
$route = $this->getMockBuilder('Cake\Routing\Route\Route')
->setMethods(['parse'])
->setConstructorArgs(['/forward', ['controller' => 'Articles', 'action' => 'index']])
->getMock();

$route->expects($this->once())
->method('parse')
->with('/forward', 'GET')
->will($this->returnValue('works!'));

$request = new ServerRequest([
'environment' => [
'REQUEST_METHOD' => 'GET',
'PATH_INFO' => '/forward'
]
]);
$result = $route->parseRequest($request);
}

/**
* Test that parseRequest() applies host conditions
*
* @return void
*/
public function testParseRequestHostConditions()
{
$route = new Route(
'/fallback',
['controller' => 'Articles', 'action' => 'index'],
['_host' => '*.example.com']
);

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'a.example.com',
'PATH_INFO' => '/fallback'
]
]);
$result = $route->parseRequest($request);
$expected = [
'controller' => 'Articles',
'action' => 'index',
'pass' => [],
'_matchedRoute' => '/fallback'
];
$this->assertEquals($expected, $result, 'Should match, domain is correct');

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'foo.bar.example.com',
'PATH_INFO' => '/fallback'
]
]);
$result = $route->parseRequest($request);
$this->assertEquals($expected, $result, 'Should match, domain is a matching subdomain');

$request = new ServerRequest([
'environment' => [
'HTTP_HOST' => 'example.test.com',
'PATH_INFO' => '/fallback'
]
]);
$this->assertFalse($route->parseRequest($request));
}

/**
* test the parse method of Route.
*
Expand Down

0 comments on commit 791cce6

Please sign in to comment.