Dancer - new suggestion - "route namespace"
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
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
Sorry for the slow reply - been busy, and haven't had time to give it the attention it deserves. Firstly, multi-app support is going to be a *lot* better and cleaner in Dancer2, so I doubt we want to do any really major overhauling of Dancer for this, we'd be better off just getting Dancer2 ready for primetime :) Having said that, though, it seems you might have spotted something: On Sunday 20 November 2011 14:40:43 Perlover wrote:
Good day!
I found a buggy behavior of Dancer with multiply application configuration and routes. [...] .... 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. [...]
At a quick glance, it sounds like you might have found the source of the issue some people have seen using multiple apps via Apache2 / Plack, where requests sometimes hit the wrong app. I'm not entirely sure, though. [...]
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')
I'm not entirely sure this is required; I think the main fix, if it is required, is to make sure that the code that looks for matching routes can only ever consider routes within the app which is executing, if that's where the problem is. Personally, I'm not all that familiar with setting up multiple appps via Plack::Builder stuff - in my usage, I've always just started up apps separately via Starman, giving great performance and isolation, and letting me tweak the number of worker processes per-app appropriately, etc, then stick Nginx in front as a caching proxy (and ready to be replaced with a load balancer if the load grows enough to require sharing across boxes). Anyone else have any thoughts on this?
Good day!
Firstly, multi-app support is going to be a *lot* better and cleaner in Dancer2, so I doubt we want to do any really major overhauling of Dancer for this, we'd be better off just getting Dancer2 ready for primetime :)
I cannot use Dancer2 I need use a stable version of Dancer for my projects
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. [...]
At a quick glance, it sounds like you might have found the source of the issue some people have seen using multiple apps via Apache2 / Plack, where requests sometimes hit the wrong app.
Yes, but i use Starman + Dancer :-) And use nginx before for static files.
I'm not entirely sure, though.
[...]
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')
I'm not entirely sure this is required; I think the main fix, if it is required, is to make sure that the code that looks for matching routes can only ever consider routes within the app which is executing, if that's where the problem is.
But this code in Dancer! Dancer's code looks for matching routes. I cannot fix this problem without fixing of Dancer
Personally, I'm not all that familiar with setting up multiple appps via Plack::Builder stuff - in my usage, I've always just started up apps separately via Starman, giving great performance and isolation, and letting me tweak the number of worker processes per-app appropriately, etc, then stick Nginx in front as a caching proxy (and ready to be replaced with a load balancer if the load grows enough to require sharing across boxes).
As i wrote above i use Starman + Dancer too But i don't want use an one Dancer + Starman bundle for one virtual site And more - it's problem FOR ONE SITE for me As i wrote above i wanted to use middleware Plack::Middleware::Auth::Basic for one one path and other path without this middleware. And in this configuration i have a problem - protected data are accessed through public requests and there are random mix of routes for requests... I resolved a problem for me (https://github.com/Perlover/Dancer the branch new/mount_at and to see https://github.com/sukria/Dancer/pull/701) but after i suggested more standardable workaround. But if you want to make Dancer better i think you should research this suggestion :-) Ok, may be anybody will research this suggestion too? Perlover
Anyone else have any thoughts on this?
_______________________________________________ Dancer-users mailing list Dancer-users@perldancer.org http://www.backup-manager.org/cgi-bin/listinfo/dancer-users
On Wednesday 23 November 2011 11:03:05 Perlover wrote:
Good day!
Firstly, multi-app support is going to be a *lot* better and cleaner in Dancer2, so I doubt we want to do any really major overhauling of Dancer for this, we'd be better off just getting Dancer2 ready for primetime :)
I cannot use Dancer2 I need use a stable version of Dancer for my projects
Sorry, I wasn't suggesting using Dancer2 right yet, it's not yet fully complete; I meant that we should focus on getting Dancer2 to the point where it is stable, backwards compatible and ready for use, as it has been redesigned from the ground up to provide better separation between apps, proper scoping etc.
At a quick glance, it sounds like you might have found the source of the issue some people have seen using multiple apps via Apache2 / Plack, where requests sometimes hit the wrong app.
Yes, but i use Starman + Dancer :-) And use nginx before for static files.
Fair enough - but multiple apps within one app.psgi file, so you're seeing the same kind of issue I think.
I'm not entirely sure this is required; I think the main fix, if it is required, is to make sure that the code that looks for matching routes can only ever consider routes within the app which is executing, if that's where the problem is.
But this code in Dancer! Dancer's code looks for matching routes. I cannot fix this problem without fixing of Dancer
Sorry, what I meant when I said I wasn't sure "this" was required was the addition of a route namespace keyword and/or option to pass when declaring route handlers; that should be taken care of for you by Dancer, it should kno which app a route handler belongs to. I didn't mean that the route-matching stuff shouldn't be fixed, if indeed it is broken, which it seems likely to be.
As i wrote above i use Starman + Dancer too But i don't want use an one Dancer + Starman bundle for one virtual site And more - it's problem FOR ONE SITE for me
One site, but loading multiple apps via it, so you're in the same situation. My point was that I personally haven't used Plack::Builder to assemble multiple apps into one. Thanks for your efforts on this, by the way!
Sorry, what I meant when I said I wasn't sure "this" was required was the addition of a route namespace keyword and/or option to pass when declaring route handlers; that should be taken care of for you by Dancer, it should kno which app a route handler belongs to.
Yes, i think too But Dancer know handles a routes without matching of applications If you will look code detailed you will see there it And some tests of Dancer will not work if Dancer will match application too for routes Please to see the test t/00_base/09_load_app.t - it will not work I suggest a soft way for resolving this and other same problems with random mix routes - backward compatible My patch is working now and all tests are passed
As i wrote above i use Starman + Dancer too But i don't want use an one Dancer + Starman bundle for one virtual site And more - it's problem FOR ONE SITE for me
One site, but loading multiple apps via it, so you're in the same situation.
But Dancer has a multi application code. I suggest to me don't use it?
My point was that I personally haven't used Plack::Builder to assemble multiple apps into one.
This is suggested by Dancer in examples in Dancer::Deployment So i think it should be deleted from there
Thanks for your efforts on this, by the way!
Best regards I will use my patched version And this maillist will have a regular problems from users with route problems
Ok, soon i will make a patch for this I have one but as 'mount_at' option I will make a branch for route_namespace If authors of Dancer will want to use it - welcome But i will use my own patched version of Dancer because no ways for normal work of Dancer with mounting of Plack::Builder Bye
participants (2)
-
David Precious -
Perlover