Good day! Does anybody have thoughts about this idea? :) Best regards, Perlover 2011/11/20 Perlover <perlover@perlover.com>:
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