[NFR] Hostname routing #371

Closed
tugrul opened this Issue Jan 30, 2013 · 17 comments

Projects

None yet

10 participants

@tugrul
Contributor
tugrul commented Jan 30, 2013

I like routing component very much! It's very simple and very efficient.

I needed hostname routing like Zend_Controller_Router_Route_Hostname but Zend's chaining router approach is very inefficient.

Maybe the hostname routing can be like \Phalcon\Mvc\Router\Group

Following use case in my mind.

<?php
$router = new \Phalcon\Mvc\Router();

//Create a group with a hostname 
// \Phalcon\Mvc\Router\Group\Hostname extends \Phalcon\Mvc\Router\Group
$user = new \Phalcon\Mvc\Router\Group\Hostname('{username:\w+}.example.com', array(
    'controller' => 'user'
    'action' => 'index'
));

// easy way to implement to API but inefficient approach
$user->setHostname('john.example.com'); // else falling back with $_SERVER['HTTP_HOST']

// or

// hard way to implement to API but more efficient approach
$router->setHostname('john.example.com'); // else falling back with $_SERVER['HTTP_HOST']

//Add a route to the group
$user->add('/images', array(
    'action' => 'images'
));

//Add a route to the group
$user->add('/comments', array(
    'action' => 'comments'
));

//Add the group to the router
$router->mount($user);
@x51xxx
x51xxx commented Jan 30, 2013

+1

@alexvlasov

+1

@roman-kulish

It can be a highly anticipated feature when it comes to e.g, ReST services hosted at the same server under different sub-domain. I did similar project in the past and in my code I do domain detection and mount specific routes, which is a pain in the back bottom obviously as it can be simplified.

I think it should be a feature of both \Phalcon\Mvc\Router\Group and \Phalcon\Mvc\Router:

$routes_group = new \Phalcon\Mvc\Router\Group();
$routes_group->setHostname('api.example.com');

$router = new \Phalcon\Mvc\Router();
$router->setDefaultHostname('example.com');

// ...

$router->mount($routes_group);
$router->add('/some/path')->via(array('POST', 'PUT'))->setHostname('api.example.com');

There are couple of drawbacks:

  • custom port, how will they work?
  • hostname itself is better to be a regex. Simple scenario is when you use a pool of services www1.example.com, www2. example.com etc; or when you alias www.example.com to example.com.
@tugrul
Contributor
tugrul commented Feb 7, 2013

@roman-kulish not required. Because mine approach provide solution also your problem like following.

// API routes
$apiGroup = new \Phalcon\Mvc\Router\Group\Hostname('api.example.com', array(
    'module' => 'api'
));
$apiGroup->add('/user/{user}/comments', array('controller'=>'comments', 'action'=>'post'))->via(array('POST','PUT');

// Site routes
$siteGroup = new \Phalcon\Mvc\Router\Group\Hostname('example.com', array(
    'module' => 'site'
));
$siteGroup->add('/user/{user}/comments', array('controller'=>'comments', 'action'=>'get'));

$router = new \Phalcon\Mvc\Router();
$router->mount($siteGroup);
$router->mount($apiGroup);

Also you can make route for SaaS like following:

// API routes
$apiGroup = new \Phalcon\Mvc\Router\Group\Hostname('api.{domain:.+}', array(
    'module' => 'api'
));
$apiGroup->add('/user/{user}/comments', array('controller'=>'comments', 'action'=>'post'))->via(array('POST','PUT');

// Site routes
$siteGroup = new \Phalcon\Mvc\Router\Group\Hostname('{domain:.+}', array(
    'module' => 'site'
));
$siteGroup->add('/user/{user}/comments', array('controller'=>'comments', 'action'=>'get'));

$router = new \Phalcon\Mvc\Router();
$router->mount($siteGroup);
$router->mount($apiGroup);
@roman-kulish

I am just saying that it is not worth to create another entity which would repeat 99% of functionality with only difference which is hostname routing.

@tugrul
Contributor
tugrul commented Feb 9, 2013

@roman-kulish ok i understand. I think should be init function to initialize default config on base class like following:

namespace \My\Router\Group;

class Hostname extends \Phalcon\Mvc\Router\Group\Hostname
{
    public function initialize()
    {
        $this->add('/user/{user}/comments', array('controller'=>'comments', 'action'=>'post'))->via(array('POST','PUT');
        $this->add('/user/images/{id}', array('controller' => 'images', 'action'=>'show'));
    }
}

$router = new \Phalcon\Mvc\Router();
$router->mount(new \My\Router\Group\Hostname('api.example.com', array('module' => 'api' )));
$router->mount(new \My\Router\Group\Hostname('example.com', array('module' => 'site')));
@phalcon
phalcon commented Feb 18, 2013

We're now working on this request as part of 1.0.0

@jarvischen

+1

@zhengjinhua

+1

@roman-kulish

How are you going to resolve hostname spoofing, when someone can fake "Host: " header in the request? It's a minor problem though but it may lead to bigger problems if a developer is not aware of it.

@tugrul
Contributor
tugrul commented Mar 25, 2013

@roman-kulish it's not problem. There isn't any webserver who has got a solution. This is already nature of HTTP 1.1.

http://stackoverflow.com/questions/246859/http-1-0-vs-1-1

You can try like following:

curl -I -H "Host: adsense.blogspot.com" http://173.194.35.170/
curl -I -H "Host: google.blogspot.com" http://173.194.35.170/

This is a not problem.

@phalcon
phalcon commented Apr 16, 2013

This is implemented in 1.1.0, check this out http://blog.phalconphp.com/post/48089073098/phalcon-1-1-beta-released

@phalcon phalcon closed this Apr 16, 2013
@tugrul
Contributor
tugrul commented Apr 16, 2013

Thanks..

I think the implementation is not useful because looks like there isn't any pattern matching for hostname like url.

@phalcon
phalcon commented Apr 16, 2013

Regular expressions also are going to be supported in this version

$route->setHostName('{domain:[a-z]+}.phalconphp.com')
@alpaxo
alpaxo commented Jul 3, 2013

it seems regexp in hostname does not work for either route neither group (1.1/1.2)

@Cmssspl
Cmssspl commented Jan 5, 2014

$route->setHostName({domain:.*}.phalcon')

Dont work in 1.2.4, plzz fix. ;-)

@ryanwalters

The regex example given by @phalcon does not work in 1.3.1:

$router->add(...)->setHostname('{username:[a-z]+}.domain.com');

Please fix!

Edit:
If this feature is working but we're just implementing it improperly, it would be very helpful to see the documentation updated to include an example of how to use this.

The following example from the documentation works:

...->setHostName('([a-z+]).company.com');

But there are no examples which use variables like:

...->setHostname('{username:[a-z]+}.company.com');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment