[Dancer-users] Dancer - new suggestion - "route namespace"
Perlover
perlover at perlover.com
Sun Nov 20 15:40:43 CET 2011
Good day!
I found a buggy behavior of Dancer with multiply application
configuration and routes.
Please to see example in current Dancer::Deployment -> Running
multiple apps with Plack::Builder
[...]
builder {
mount "/app1" => builder {$app1};
mount "/app2" => builder {$app2};
};
Here 'mount' through Plack::App::URLMap->map will call our $app1 &
$app2 BUT /app1 & /app2 will be removed from $request->path_info!
Our applications will get a new path_info paths. Imagine a following example:
builder {
mount "/app1" => builder {$app1};
mount "/app2" => builder { enable "Auth::Basic",
authenticator => \&authen_cb; $app2};
};
Here $app2 is protected by Plack::Middleware::Auth::Basic and it has
some /admin/* routes (for /app2/admin/... urls)
But $app has only one root routes for example as '/' (and may be other routes)
Now please to see the source of module Dancer::App, lines 104-106:
....
sub find_route_through_apps {
my ($class, $request) = @_;
for my $app (Dancer::App->current, Dancer::App->applications) {
my $route = $app->find_route($request);
....
Here we see that searching is going until the target route will be
found in all applications!
Imagine that we requested the url /app1/admin/... What happens?
The $app1 will get path_info as /admin/... after Plack::App::URLMap
and Dancer will start a searching in find_route_through_apps and will
find a route of $app2!
And it will call it code without middleware Auth! And protected and
security data will be given for remote user without protection!
What is result? The /app1/ URLs will sometimes run app2's routes, the
/app2/ URLs will sometimes run a routes of app1 and so on.
And in above example we will get a security hole additional...
---------------------------------------
What i suggest ?
I think Dancer should have:
1) For get & post now we can pass an options hashref before code like
this get '/' => {option1 =>..., ...}, sub {} (i see this in code of
Dancer but i didn't find it in docs) . I think there should be option
'route_namespace' for example. If it defined it consists a namespace
of this route. If not defined it has a namespace defined in
route_namespace command (point 2 here)
2) Should be command like 'prefix' but named as 'route_namespace' fro
setting up namespace of routes of this application. The prefix option
for real pieces in $request->path_info but this route_namespace for
virtual because we cannot get a namespace from path_info (only from
$request->script_name but i want to make this behavior flexible for
'route_namespace')
3) I think the object Dancer::Request should have a method
(getter/setter) route_namespace. Through this method we can setup a
namespace of current request for searching of routes. If we set up for
example $request->route_namespace('app1') before
Dancer->dance($request) (example in Dancer::Deployment -> Running
multiple apps with Plack::Builder) for example then the
find_route_through_apps should search through all applications all
routes BUT with same namespace only. If route_namespace is not defined
for current $request a behavior is as now (backward compatible)
So after this patches our example in Dancer::Deployment will look like:
use Dancer ':syntax';
use Plack::Builder;
setting apphandler => 'PSGI';
my $app1 = sub {
my $env = shift;
local $ENV{DANCER_APPDIR} = '/Users/franck/tmp/app1';
load_app "app1"; # In the app1 module we have command:
route_namespace "app1" before routes
# May be here we should be
able to setup too like: load_app "app1", route_namespace => 'app1';
Dancer::App->set_running_app('app1');
setting appdir => '/Users/franck/tmp/app1';
Dancer::Config->load;
my $request = Dancer::Request->new( env => $env
)->route_namespace('app1'); # route_namespace as setter returns an
instance of Dancer::Request
Dancer->dance($request); # Now the Dancer knows in the
find_route_through_apps what we want (only routes from "app1"
namespace)
};
my $app2 = sub {
my $env = shift;
local $ENV{DANCER_APPDIR} = '/Users/franck/tmp/app2';
load_app "app2"; # In the app2 module we have command:
route_namespace "app2" before routes
Dancer::App->set_running_app('app2');
setting appdir => '/Users/franck/tmp/app2';
Dancer::Config->load;
my $request = Dancer::Request->new( env => $env
)->route_namespace('app2'); # route_namespace as setter returns an
instance of Dancer::Request;
Dancer->dance($request); # Now the Dancer knows in the
find_route_through_apps what we want (only routes from "app2"
namespace)
};
builder {
mount "/app1" => builder {$app1};
mount "/app2" => builder { enable "Auth::Basic",
authenticator => \&authen_cb; $app2};
};
Your opinions?
I can make all this patches in Dancer for devel branch at github
But before i want to listen from you some suggestions and opinions
Thanks!
Perlover
More information about the Dancer-users
mailing list