CGI::Application::Dispatch - Class used to dispatch request to CGI::Application based objects
<Location /app> SetHandler perl-script PerlHandler CGI::Application::Dispatch </Location>
#!/usr/bin/perl use strict; use CGI::Application::Dispatch; CGI::Application::Dispatch->dispatch();
This module provides a way (as a mod_perl handler or running under vanilla CGI) to look at the path ($r->path_info or $ENV{PATH_INFO}) of the incoming request, parse off the desired module and it's run mode, create an instance of that module and run it.
$r->path_info
$ENV{PATH_INFO}
It currently supports both generations of mod_perl (1.x and 2.x). Although, for simplicity, all examples involving apache configuration and mod_perl code will be shown using mod_perl 1.x. This may change as mp2 usage increases.
In addition, the portion of the PATH_INFO that is used to derive the module name is also passed to the PARAMS of the modules <new()> as CGIAPP_DISPATCH_PATH. This can be useful if you are programatically generating URLs.
PATH_INFO
PARAMS
<new()
It will translate a URI like this (under mod_perl):
/app/module_name/run_mode
or this (vanilla cgi)
/app/index.cgi/module_name/run_mode
into something that will be functionally similar to this
my $app = Module::Name->new(..); $app->mode_param(sub {'run_mode'}); #this will set the run mode
And in both cases the CGIAPP_DISPATCH_PATH value will be 'module_name' so that you can generate a self referential URL by doing something like the following inside of your application module:
my $url = 'http://mysite.com/app/' . $self->param('CGIAPP_DISPATCH_PATH');
To be honest I got tired of writing lots of individual instance scripts, one for each application module, under the traditional style of CGI::Application programming. Then when I switched to running my CGI::Application modules as straight mod_perl handlers I got tired of having to change my httpd.conf file for every module I introduced and having my configuration file full of Location sections. Since I had moved all of my configuration variables into config files and was not passing any values into the PARAMS hash upon module creation I decided not to write the same code over and over.
Location
I guess it comes down to me just being lazy. :)
This section describes the different options that are available to customize how you dispatch your requests. All of these options can either be set using 'PerlSetVar' (if you're running under mod_perl) or passed directly as name-value pairs to the "dispatch()" method. When passing them directly as name-value pairs to the "dispatch()" method you may omit the 'CGIAPP_DISPATCH_' prefix on the name of each option. So, CGIAPP_DISPATCH_PREFIX can become simply PREFIX. You can't however use both. We have examples so don't worry too much.
CGIAPP_DISPATCH_PREFIX
PREFIX
This option will set the string that will be prepended to the name of the application module before it is loaded and created. So to use our previous example request of
This would by default load and create a module named 'Module::Name'. But let's say that you have all of your application specific modules under the 'My' namespace. If you set this option to 'My' then it would instead load the 'My::Module::Name' application module instead.
This option, if false, will tell C::A::Dispatch to not set the run mode for the application. By default it is true.
This option will set a default value if there is no $ENV{PATH_INFO}. It will be parsed to obtain the module name and run mode (if you don't have CGIAPP_DISPATCH_RM set to false.
CGIAPP_DISPATCH_RM
This option will tell CGI::Application::Dispatch to use either a provided hash or subroutine to translate the $ENV{PATH_INFO} into the module name. The retrieved value will also be combined with the CGIAPP_DISPATCH_PREFIX value if it exists.
TABLE with mod_perl
If you are using this under mod_perl and enjoy using PerlAddVar directives, then your httpd.conf might look something like this (under mod_perl 1)
<Location /app> SetHandler perl-script PerlHandler CGI::Application::Dispatch PerlSetVar CGIAPP_DISPATCH_PREFIX MyApp PerlSetVar CGIAPP_DISPATCH_RM Off PerlSetVar CGIAPP_DISPATCH_TABLE foo PerlAddVar CGIAPP_DISPATCH_TABLE Some::Name PerlAddVar CGIAPP_DISPATCH_TABLE bar PerlAddVar CGIAPP_DISPATCH_TABLE Some::OtherName PerlAddVar CGIAPP_DISPATCH_TABLE baz PerlAddVar CGIAPP_DISPATCH_TABLE Yet::AnotherName </Location>
And then Dispatch will turn the all those PerlSetVar and PerlAddVars into a hash.
TABLE with vanilla CGI
Or if you are using Dispatch under vanilla cgi then an equivalent .cgi script would be:
#!/usr/bin/perl use strict; use CGI::Application::Dispatch; CGI::Application::Dispatch->dispatch( PREFIX => 'MyApp', RM => 0, TABLE => { 'foo' => 'Some::Name', 'bar' => 'Some::OtherName', 'baz' => 'Yet::AnotherName', }, );
In all these cases a url or '/foo/rm2' will be translated into the module 'MyApp::Some::Name' and run mode 'rm2'. This will allow more flexibility in PATH_INFO to module name translation and also provide more security for those who want to restrict what options are available for translation. If the PATH_INFO contains a value that is not a key in your table hash, then Dispatch will t
This method is used so that this module can be run as a mod_perl handler. When it creates the application module it passes the $r argument into the PARAMS hash of new()
<Location /app> SetHandler perl-script PerlHandler CGI::Application::Dispatch PerlSetVar CGIAPP_DISPATCH_PREFIX MyApp PerlSetVar CGIAPP_DISPATCH_RM Off PerlSetVar CGIAPP_DISPATCH_DEFAULT /module_name </Location>
The above example would tell apache that any url beginning with /app will be handled by CGI::Application::Dispatch. It also sets the prefix used to create the application module to 'MyApp' and it tells CGI::Application::Dispatch that it shouldn't set the run mode but that it will be determined by the application module as usual (through the query string). It also sets a default application module to be used if there is no PATH_INFO. So, a url of /app/module_name would create an instance of MyApp::Module::Name.
/app/module_name
MyApp::Module::Name
This method is primarily used in a non mod_perl setting in an small cgi script to dispatch requests. You can pass this method the same name value pairs that you would set for the "handler()" method using the same options mentioned above.
#!/usr/bin/perl use strict; use CGI::Application::Dispatch; CGI::Application::Dispatch->dispatch( PREFIX => 'MyApp', RM => 0, DEFAULT => 'module_name', );
This example would do the same thing that the previous example of how to use the "handler()" method would do. The only difference is that it is done in a script and not in the apache configuration file.
The benefit to using CGI::Application::Dispatch in a non mod_perl environment instead of the traditional instance scripts would only be seen in an application that has many instance scripts. It would mean your application would only need one script and many application modules. Since the dispatch script is so simple you just write it once and forget about it and turn your attention to your modules and templates.
Any extra params to dispatch() will be passed on to the new() method of the CGI::Application module being called.
This method is used to control how the module name is generated from the PATH_INFO. Please see "PATH_INFO Parsing" for more details on how this method performs it's job. The main reason that this method exists is so that it can be overridden if it doesn't do exactly what you want.
This method will recieve three arguments in the following order:
$path_info
The PATH_INFO string
$prefix
The value of the CGIAPP_DISPATCH_PREFIX parameter.
$table
A hash reference containing the value of the CGIAPP_DISPATCH_TABLE parameter.
This method will return the name of the module to create. Actually it returns a list of items, the first being the name of the module, the second being the specific substring of the PATH_INFO that was used to create the module name. If you decide to override this method to customize the PATH_INFO-to-module-name-creation then you must also return this section of the PATH_INFO that you used if it's not the same as the default. Otherwise the value of CGIAPP_DISPATCH_PREFIX will be undef.
undef
This method is used to control how the run mode is generated from the PATH_INFO. Please see "PATH_INFO Parsing" for more details on how this method performs it's job. The main reason that this method exists is so that it is overridden if it doesn't do exactly what you want.
You shouldn't actually call this method yourself, just override it if necessary.
This class method is used internally by CGI::Application::Dispatch to take a module name (supplied by get_module_name) and require it in a secure fashion. It is provided as a public class method so that if you override other functionality of this module, you can still safely require user specified modules. If there are any problems requiring the named module, the $CGI::Application::Dispatch::Error variable will be set.
$CGI::Application::Dispatch::Error
CGI::Application::Dispatch->require_module('MyApp::Module::Name'); if( $CGI::Application::Dispatch::Error ) { die "Could not require module MyApp::Module::Name " . $CGI::Application::Dispatch::Error }
This section will describe how the application module and run mode are determined from the PATH_INFO and what options you have to customize the process.
To put it simply, if you don't use a CGIAPP_DISPATCH_TABLE then the PATH_INFO is split on backslahes (/). The second element of the returned list is used to create the application module. So if we have a path info of
/
/module_name/mode1
Then the string 'module_name' is used. Underscores (_) are turned into double colons (::) and each word is passed through ucfirst so that the first letter of each word is captialized.
_
::
ucfirst
Then the CGIAPP_DISPATCH_PREFIX is added to the beginning of this new module name with a double colon :: separating the two.
If you don't like the exact way that this is done, don't fret you do have a couple of options. First, you can specify a CGIAPP_DISPATCH_TABLE on a project-by-project basis to explicitly perform the PATH_INFO to module-name translation. If you are looking for something more generic that you can later reuse, you can subclass Dispatch and override the get_module_name() to do whatever you wish.
Just like the module name is retrieved from splitting the PATH_INFO on backslashes, so is the run mode. Only instead of using the second element of the resulting list, we use the third as the run mode. So, using the same example, if we have a path info of
Then the string 'mode1' is used as the run mode unless the CGIAPP_DISPATCH_RM is set to false. As with the module name this behavior can be changed by overriding the get_runmode() sub.
CGI query strings
CGI query strings are unaffected by the use of PATH_INFO to obtain the module name and run mode. This means that any other modules you use to get access to you query argument (ie, CGI, Apache::Request) should not be affected. But, since the run mode may be determined by CGI::Application::Dispatch having a query argument named 'rm' will be ignored by your application module (unless your CGIAPP_DISPATCH_RM is false).
Michael Peters <mpeters@plusthree.com>
Thanks to Plus Three, LP (http://www.plusthree.com) for sponsoring my work on this module
This module is a part of the larger CGI::Application community. If you have questions or comments about this module then please join us on the cgiapp mailing list by sending a blank message to "cgiapp-subscribe@lists.erlbaum.net". There is also a community wiki located at http://www.cgi-app.org/
Drew Taylor <drew@drewtaylor.com>
James Freeman <james.freeman@smartsurf.org>
Michael Graham <magog@the-wire.com>
Cees Hek <ceeshek@gmail.com>
Since C::A::Dispatch will dynamically choose which modules to use as the content generators, it may give someone the ability to execute random modules on your system if those modules can be found in you path. Of course those modules would have to behave like CGI::Application based modules, but that still opens up the door more than most want. This should only be a problem if you don't use the CGIAPP_DISPATCH_PREFIX (or simple PREFIX in "dispatch()") option. By using this option you are only allowing the url to pick from a certain directory (namespace) of applications to run.
CGI::Application, Apache::Dispatch
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install CGI::Application::Dispatch, copy and paste the appropriate command in to your terminal.
cpanm
cpanm CGI::Application::Dispatch
CPAN shell
perl -MCPAN -e shell install CGI::Application::Dispatch
For more information on module installation, please visit the detailed CPAN module installation guide.