| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Apache2::Controller::Dispatch; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | Apache2::Controller::Dispatch - dispatch base class for Apache::Controller | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 VERSION | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | Version 1.001.001 | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | =cut | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 2 |  |  | 2 |  | 3163 | use version; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 16 |  | 
| 14 |  |  |  |  |  |  | our $VERSION = version->new('1.001.001'); | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | Synopsis examples use L, | 
| 19 |  |  |  |  |  |  | but you may want to check out L | 
| 20 |  |  |  |  |  |  | or write your own.  All use the C<< A2C_Dispatch_Map >> directive, | 
| 21 |  |  |  |  |  |  | but the hash structure differs between subclasses. | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | =head2 EASY WAY | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | This only works if you have one website on the whole server (under forked mpm) | 
| 26 |  |  |  |  |  |  | because the intepreter only loads the module once and then it won't | 
| 27 |  |  |  |  |  |  | load another dispatch map for other uri's. | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | # vhost.conf: | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | SetHandler modperl | 
| 32 |  |  |  |  |  |  | A2C_Dispatch_Map   /path/to/yaml/syck/dispatch/hash/file.yaml | 
| 33 |  |  |  |  |  |  | PerlInitHandler    Apache2::Controller::Dispatch::Simple | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | =head2 NORMAL WAY | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | The normal way supports many separate dispatch maps on a server, | 
| 39 |  |  |  |  |  |  | but each application must subclass a dispatch class, even if it | 
| 40 |  |  |  |  |  |  | has no methods. | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | # vhost.conf: | 
| 43 |  |  |  |  |  |  | PerlLoadModule MyApp::Dispatch; | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | SetHandler modperl | 
| 46 |  |  |  |  |  |  | A2C_Dispatch_Map   /etc/myapp/dispatch.yaml | 
| 47 |  |  |  |  |  |  | PerlInitHandler    MyApp::Dispatch | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | # /etc/myapp/dispatch.yaml: | 
| 51 |  |  |  |  |  |  | foo:       MyApp::Controller::Foo | 
| 52 |  |  |  |  |  |  | bar:       MyApp::Controller::Bar | 
| 53 |  |  |  |  |  |  | 'foo/bar': MyApp::Controller::Foo::Bar | 
| 54 |  |  |  |  |  |  | biz:       MyApp::C::Biz | 
| 55 |  |  |  |  |  |  | 'biz/baz': MyApp::Controller::Biz::Baz | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | # lib/MyApp/Dispatch.pm: | 
| 58 |  |  |  |  |  |  | package MyApp::Dispatch; | 
| 59 |  |  |  |  |  |  | use base qw( Apache2::Controller::Dispatch::Simple ); | 
| 60 |  |  |  |  |  |  | 1; | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | =head2 HARD WAY | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | # vhost.conf: | 
| 65 |  |  |  |  |  |  | PerlModule MyApp::Dispatch | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | SetHandler modperl | 
| 69 |  |  |  |  |  |  | PerlInitHandler MyApp::Dispatch | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | # lib/MyApp/Dispatch.pm: | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | package MyApp::Dispatch; | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | use strict; | 
| 77 |  |  |  |  |  |  | use warnings FATAL => 'all'; | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | use base qw( Apache2::Controller::Dispatch::Simple ); | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | # return a hash reference from dispatch_map() | 
| 82 |  |  |  |  |  |  | sub dispatch_map { return { | 
| 83 |  |  |  |  |  |  | foo        => 'MyApp::C::Foo', | 
| 84 |  |  |  |  |  |  | bar        => 'MyApp::C::Bar', | 
| 85 |  |  |  |  |  |  | 'foo/bar'  => 'MyApp::C::Foo::Bar', | 
| 86 |  |  |  |  |  |  | biz        => 'MyApp::C::Biz', | 
| 87 |  |  |  |  |  |  | 'biz/baz'  => 'MyApp::C::Biz::Baz', | 
| 88 |  |  |  |  |  |  | } } | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | # or use directive A2C_Dispatch_Map to refer to a YAML file. | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | 1; | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | C forms the base for the | 
| 97 |  |  |  |  |  |  | PerlInitHandler module to dispatch incoming requests to | 
| 98 |  |  |  |  |  |  | libraries based on their URL. | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | You don't use this module.  You use one of its subclasses | 
| 101 |  |  |  |  |  |  | as a base for your dispatch module. | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =head1 WHY A MAP? | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | Natively, this does not try to figure out the appropriate | 
| 106 |  |  |  |  |  |  | module using any complex magic.  Instead, you spell out the | 
| 107 |  |  |  |  |  |  | uris under the handler location and what controller | 
| 108 |  |  |  |  |  |  | modules you want to handle paths under that URL, using a | 
| 109 |  |  |  |  |  |  | directive. (L) | 
| 110 |  |  |  |  |  |  |  | 
| 111 |  |  |  |  |  |  | The trouble with automatic controller module detectors is | 
| 112 |  |  |  |  |  |  | that parsing the URI and doing C<< eval "use lib $blah" >> | 
| 113 |  |  |  |  |  |  | up through the URI path is that is computationally expensive. | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | Maintaining a URI map file is not that difficult and also is | 
| 116 |  |  |  |  |  |  | convenient because you can move libraries around, point different | 
| 117 |  |  |  |  |  |  | URI's to the same controller library, etc.  For example to bring | 
| 118 |  |  |  |  |  |  | part of your site off-line and see 'under construction', create | 
| 119 |  |  |  |  |  |  | a controller to print the right message, change all the uri's | 
| 120 |  |  |  |  |  |  | in the map and bump the server. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | (Can I trap a signal so it | 
| 123 |  |  |  |  |  |  | clears and reloads map files if Apache2 is HUP'd?  That would be cool. | 
| 124 |  |  |  |  |  |  | Or a timeout that would cause children to reload the file.) | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | Different dispatch types use different structure in the | 
| 127 |  |  |  |  |  |  | map, but it is conceptually the same.  The structure is | 
| 128 |  |  |  |  |  |  | loaded into memory and then the uri can be parsed very | 
| 129 |  |  |  |  |  |  | quickly to locate the correct controller. | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | =head1 SUBCLASSES | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | Subclasses of this module implement C<< find_controller() >> | 
| 134 |  |  |  |  |  |  | in different ways, usually interpreting the URI from a | 
| 135 |  |  |  |  |  |  | hash reference returned by C<< dispatch_map() >> in your subclass. | 
| 136 |  |  |  |  |  |  | Or, if you provide the directive C<< A2C_Dispatch_Map >> to specify | 
| 137 |  |  |  |  |  |  | a map file, this module will load it with L. | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | See L and | 
| 140 |  |  |  |  |  |  | L for other | 
| 141 |  |  |  |  |  |  | dispatch possibilities. | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | Any implementation of find_controller() should throw an | 
| 144 |  |  |  |  |  |  | L with status C<< Apache2::Const::NOT_FOUND >> | 
| 145 |  |  |  |  |  |  | in the | 
| 146 |  |  |  |  |  |  | event that the detected method selected does not appear in the list of | 
| 147 |  |  |  |  |  |  | C<< allowed_methods() >> in the controller module.  ex: | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | a2cx status => Apache2::Const::NOT_FOUND; | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | See L.  This is | 
| 152 |  |  |  |  |  |  | internal stuff mostly, you don't have to implement your own | 
| 153 |  |  |  |  |  |  | type of dispatch mechanism unless you are a nut like me. | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | Successful run of find_controller() should result in four items of | 
| 156 |  |  |  |  |  |  | data being set in request->pnotes->{a2c}: | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | =over 4 | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =item pnotes->{a2c}{relative_uri} = matching part of uri relative to location | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | This is the uri relative to the location. For example, | 
| 163 |  |  |  |  |  |  | if the dispatch module is the init handler in a C<<  >> | 
| 164 |  |  |  |  |  |  | config block, then for /subdir/foo/bar/biz/zip in this example code, | 
| 165 |  |  |  |  |  |  | relative_uri should be 'foo/bar' because this is the key of %dispatch_map | 
| 166 |  |  |  |  |  |  | that was matched.  /subdir/foo/bar is the 'virtual directory.' | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | If there is no relative uri, for example if the uri requested was /subdir | 
| 169 |  |  |  |  |  |  | and this is the same as the location, then | 
| 170 |  |  |  |  |  |  | C< pnotes->{a2c}{relative_uri} > would be set to | 
| 171 |  |  |  |  |  |  | the empty string. | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | =item pnotes->{a2c}{controller} = selected package name | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | This should be the name (string) of an Apache2::Controller subclass selected | 
| 176 |  |  |  |  |  |  | for dispatch. | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | =item pnotes->{a2c}{method} = method name in controller to process the uri | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | This is the name of the method of the controller to use for this request. | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | =item pnotes->{a2c}{path_args} = [ remaining path_info ] | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | The remaining 'virtual directory' arguments of the uri. | 
| 185 |  |  |  |  |  |  | In the example above for pnotes->{a2c}{relative_uri}, this is [ 'biz', 'zip' ]. | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | =back | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | @path_args is the array of remaining elements.  For example if your | 
| 190 |  |  |  |  |  |  | dispatch map contains the URI 'foo', and the incoming URI was '/foo/bar/baz', | 
| 191 |  |  |  |  |  |  | then $r->pnotes->{a2c}{path_args} should be ['bar', 'baz'] before returning. | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | =cut | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 2 |  |  | 2 |  | 375 | use strict; | 
|  | 2 |  |  |  |  | 3 |  | 
|  | 2 |  |  |  |  | 67 |  | 
| 196 | 2 |  |  | 2 |  | 11 | use warnings FATAL => 'all'; | 
|  | 2 |  |  |  |  | 8 |  | 
|  | 2 |  |  |  |  | 80 |  | 
| 197 | 2 |  |  | 2 |  | 17 | use English '-no_match_vars'; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 11 |  | 
| 198 |  |  |  |  |  |  |  | 
| 199 | 2 |  |  |  |  | 721 | use base qw( | 
| 200 |  |  |  |  |  |  | Apache2::Controller::NonResponseBase | 
| 201 |  |  |  |  |  |  | Apache2::Controller::Methods | 
| 202 | 2 |  |  | 2 |  | 1142 | ); | 
|  | 2 |  |  |  |  | 2 |  | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | use Log::Log4perl qw(:easy); | 
| 205 |  |  |  |  |  |  | use Readonly; | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | use YAML::Syck; | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | use Apache2::RequestRec (); | 
| 210 |  |  |  |  |  |  | use Apache2::Connection (); | 
| 211 |  |  |  |  |  |  | use Apache2::RequestUtil (); | 
| 212 |  |  |  |  |  |  | use Apache2::Const -compile => qw( :common :http :methods ); | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | use Apache2::Controller::X; | 
| 215 |  |  |  |  |  |  | use Apache2::Controller::Const qw( @RANDCHARS $NOT_GOOD_CHARS ); | 
| 216 |  |  |  |  |  |  | use Apache2::Controller::Funk qw( log_bad_request_reason ); | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | =head1 METHODS | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | =head2 $handler->process() | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | process() is the main guts of Apache2::Controller::Dispatch logic. | 
| 223 |  |  |  |  |  |  | It calls $self->find_controller(), which is implemented in another | 
| 224 |  |  |  |  |  |  | base class.  (See L.)  If that | 
| 225 |  |  |  |  |  |  | works, then it creates an Apache2::Request object from $r, which will | 
| 226 |  |  |  |  |  |  | supposedly parse the query string once for all further handlers that | 
| 227 |  |  |  |  |  |  | create Apache2::Request objects. | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | =cut | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | sub process { | 
| 232 |  |  |  |  |  |  | my ($self) = @_; | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | my $r       = $self->{r}; | 
| 235 |  |  |  |  |  |  | my $class   = $self->{class}; | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | my $pnotes  = $r->pnotes; | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | # find the controller module and method to dispatch the URI | 
| 240 |  |  |  |  |  |  | $self->find_controller(); | 
| 241 |  |  |  |  |  |  | my $controller = $self->{controller} = $pnotes->{a2c}{controller}; | 
| 242 |  |  |  |  |  |  | DEBUG "found controller '$controller'"; | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | # save the dispatch class name in notes in case we have to | 
| 245 |  |  |  |  |  |  | # re-dispatch somewhere along the line if the uri changes | 
| 246 |  |  |  |  |  |  | # (this is done by Apache2::Controller::Auth::OpenID, for instance) | 
| 247 |  |  |  |  |  |  | $pnotes->{a2c}{dispatch_class} = $class; | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | # set the handler for that class | 
| 250 |  |  |  |  |  |  | # - this has to be the last thing it does in case an exception is thrown | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | DEBUG "setting PerlResponseHandler '$controller'"; | 
| 253 |  |  |  |  |  |  | $r->set_handlers(PerlResponseHandler => [ "$controller" ]); | 
| 254 |  |  |  |  |  |  | # "" == lame but true, must stringify lib name because | 
| 255 |  |  |  |  |  |  | # the value is some kind of blessed scalar reference or something | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | DEBUG sub { "Done with process() for uri ".$r->uri }; | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | return Apache2::Const::OK; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | =head2 dispatch_map | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | The base class method relies on having directive C<< A2C_Dispatch_Map >>. | 
| 265 |  |  |  |  |  |  | This loads a L file at server startup for every instance | 
| 266 |  |  |  |  |  |  | of the directive.  This is your best bet if you want to use a file, | 
| 267 |  |  |  |  |  |  | because the file will be loaded only once, instead of every time a | 
| 268 |  |  |  |  |  |  | mod_perl child process spawns. | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | If you want to return a hash yourself, overload this in a | 
| 271 |  |  |  |  |  |  | dispatch subclass. | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | =cut | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | sub dispatch_map { | 
| 276 |  |  |  |  |  |  | my ($self) = @_; | 
| 277 |  |  |  |  |  |  | return $self->get_directive('A2C_Dispatch_Map') | 
| 278 |  |  |  |  |  |  | || a2cx "No directive A2C_Dispatch_Map"; | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | =head2 get_dispatch_map | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | Get the cached C<< \%dispatch_map >> of the dispatch handler object's class. | 
| 284 |  |  |  |  |  |  | Caches references here in parent package space and checks with C<< exists >>. | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | In your dispatch subclass, you define C<< dispatch_map() >> which | 
| 287 |  |  |  |  |  |  | returns a hash reference of the dispatch map. | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | =cut | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | my %dispatch_maps = ( ); | 
| 292 |  |  |  |  |  |  | sub get_dispatch_map { | 
| 293 |  |  |  |  |  |  | my ($self) = @_; | 
| 294 |  |  |  |  |  |  | my $class = $self->{class}; | 
| 295 |  |  |  |  |  |  | return $dispatch_maps{$class} if exists $dispatch_maps{$class}; | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | my $dispatch_map = $self->dispatch_map(); | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | a2cx "No dispatch_map() in $class" if !$dispatch_map; | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | my $ref = ref $dispatch_map; | 
| 302 |  |  |  |  |  |  | a2cx "Bad dispatch_map() in $class" if !defined $ref || $ref ne 'HASH'; | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | $dispatch_maps{$class} = $dispatch_map; | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | DEBUG sub{"dispatch_maps:".Dump(\%dispatch_maps)}; | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | return $dispatch_map; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | 1; | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | =head1 EXAMPLE | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # configuration for : | 
| 317 |  |  |  |  |  |  | # PerlInitHandler MyApp::Dispatch | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | package MyApp::Dispatch; | 
| 320 |  |  |  |  |  |  | use base qw( | 
| 321 |  |  |  |  |  |  | Apache2::Controller::Dispatch | 
| 322 |  |  |  |  |  |  | Apache2::Controller::Dispatch::Simple | 
| 323 |  |  |  |  |  |  | ); | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | my @LIMIT_HTTP_METHODS = qw( GET ); | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | sub dispatch_map { {                   # return a hash reference | 
| 328 |  |  |  |  |  |  | foo        => 'MyApp::C::Foo', | 
| 329 |  |  |  |  |  |  | bar        => 'MyApp::C::Bar', | 
| 330 |  |  |  |  |  |  | biz        => 'MyApp::C::Biz', | 
| 331 |  |  |  |  |  |  | } } | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  | 1; | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | L | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | L | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | L | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | =head1 AUTHOR | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | Mark Hedges, C<<  >> | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENSE | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  | Copyright 2008-2010 Mark Hedges, all rights reserved. | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 352 |  |  |  |  |  |  | under the same terms as Perl itself. | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | This software is provided as-is, with no warranty | 
| 355 |  |  |  |  |  |  | and no guarantee of fitness | 
| 356 |  |  |  |  |  |  | for any particular purpose. | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | =cut | 
| 359 |  |  |  |  |  |  |  |