1CGI::Application::DispaUtscehr::CPoSnGtIr(i3bpumt)ed PerClGID:o:cAupmpelnitcaattiioonn::Dispatch::PSGI(3pm)
2
3
4
6 CGI::Application::Dispatch::PSGI - Dispatch requests to
7 CGI::Application based objects using PSGI
8
10 Out of Box
11 Under mod_perl:
12
13 # change "Apache1" to "Apache2" as needed.
14
15 <Location />
16 SetHandler perl-script
17 PerlHandler Plack::Handler::Apache1
18 PerlSetVar psgi_app /path/to/app.psgi
19 </Location>
20
21 <Perl>
22 use Plack::Handler::Apache1;
23 Plack::Handler::Apache1->preload("/path/to/app.psgi");
24 </Perl>
25
26 Under CGI:
27
28 This would be the instance script for your application, such as
29 /cgi-bin/dispatch.cgi:
30
31 ### in your dispatch.psgi:
32 # ( in a persistent environment, use FindBin::Real instead. )
33 use FindBin 'Bin';
34 use lib "$Bin/../perllib';
35 use Your::Application::Dispatch;
36 Your::Application::Dispatch->as_psgi;
37
38 ### In Your::Application::Dispatch;
39 package Your::Application::Dispatch;
40 use base 'CGI::Application::Dispatch::PSGI';
41
42 With a dispatch table
43 package MyApp::Dispatch;
44 use base 'CGI::Application::Dispatch::PSGI';
45
46 sub dispatch_args {
47 return {
48 prefix => 'MyApp',
49 table => [
50 '' => { app => 'Welcome', rm => 'start' },
51 ':app/:rm' => { },
52 'admin/:app/:rm' => { prefix => 'MyApp::Admin' },
53 ],
54 };
55 }
56
57 The ".psgi" file is constructed as above.
58
59 With a custom query object
60 If you want to supply your own PSGI object, something like this in your
61 .psgi file will work:
62
63 sub {
64 my $env = shift;
65 my $app = CGI::Application::Dispatch::PSGI->as_psgi(
66 table => [
67 '/:rm' => { app => 'TestApp' }
68 ],
69 args_to_new => {
70 QUERY => CGI::PSGI->new($env)
71 }
72 );
73 return $app->($env);
74 }
75
77 This module provides a way to look at the path (as returned by
78 "$env->{PATH_INFO}") of the incoming request, parse off the desired
79 module and its run mode, create an instance of that module and run it.
80
81 It will translate a URI like this (in a persistent environment)
82
83 /app/module_name/run_mode
84
85 or this (vanilla CGI)
86
87 /app/index.cgi/module_name/run_mode
88
89 into something that will be functionally similar to this
90
91 my $app = Module::Name->new(..);
92 $app->mode_param(sub {'run_mode'}); #this will set the run mode
93
95 as_psgi(%args)
96 This is the primary method used during dispatch.
97
98 #!/usr/bin/perl
99 use strict;
100 use CGI::Application::Dispatch::PSGI;
101
102 CGI::Application::Dispatch::PSGI->as_psgi(
103 prefix => 'MyApp',
104 default => 'module_name',
105 );
106
107 This method accepts the following name value pairs:
108
109 default
110 Specify a value to use for the path if one is not available. This
111 could be the case if the default page is selected (eg: "/" ).
112
113 prefix
114 This option will set the string that will be prepended to the name
115 of the application module before it is loaded and created. So to
116 use our previous example request of
117
118 /app/index.cgi/module_name/run_mode
119
120 This would by default load and create a module named
121 'Module::Name'. But let's say that you have all of your application
122 specific modules under the 'My' namespace. If you set this option
123 to 'My' then it would instead load the 'My::Module::Name'
124 application module instead.
125
126 args_to_new
127 This is a hash of arguments that are passed into the new()
128 constructor of the application.
129
130 table
131 In most cases, simply using Dispatch with the "default" and
132 "prefix" is enough to simplify your application and your URLs, but
133 there are many cases where you want more power. Enter the dispatch
134 table. Since this table can be slightly complicated, a whole
135 section exists on its use. Please see the "DISPATCH TABLE" section.
136
137 debug
138 Set to a true value to send debugging output for this module to
139 STDERR. Off by default.
140
141 auto_rest
142 This tells Dispatch that you are using REST by default and that you
143 care about which HTTP method is being used. Dispatch will append
144 the HTTP method name (upper case by default) to the run mode that
145 is determined after finding the appropriate dispatch rule. So a GET
146 request that translates into "MyApp::Module->foo" will become
147 "MyApp::Module->foo_GET".
148
149 This can be overridden on a per-rule basis in a custom dispatch
150 table.
151
152 auto_rest_lc
153 In combinaion with auto_rest this tells Dispatch that you prefer
154 lower cased HTTP method names. So instead of "foo_POST" and
155 "foo_GET" you'll have "foo_post" and "foo_get".
156
157 dispatch_args()
158 Returns a hashref of args that will be passed to dispatch(). It will
159 return the following structure by default.
160
161 {
162 prefix => '',
163 args_to_new => {},
164 table => [
165 ':app' => {},
166 ':app/:rm' => {},
167 ],
168 }
169
170 This is the perfect place to override when creating a subclass to
171 provide a richer dispatch table.
172
173 When called, it receives 1 argument, which is a reference to the hash
174 of args passed into dispatch.
175
176 translate_module_name($input)
177 This method is used to control how the module name is translated from
178 the matching section of the path (see "Path Parsing". The main reason
179 that this method exists is so that it can be overridden if it doesn't
180 do exactly what you want.
181
182 The following transformations are performed on the input:
183
184 The text is split on '_'s (underscores) and each word has its first
185 letter capitalized. The words are then joined back together and each
186 instance of an underscore is replaced by '::'.
187 The text is split on '-'s (hyphens) and each word has its first letter
188 capitalized. The words are then joined back together and each instance
189 of a hyphen removed.
190
191 Here are some examples to make it even clearer:
192
193 module_name => Module::Name
194 module-name => ModuleName
195 admin_top-scores => Admin::TopScores
196
197 require_module($module_name)
198 This class method is used internally to take a module name (supplied by
199 get_module_name) and require it in a secure fashion. It is provided as
200 a public class method so that if you override other functionality of
201 this module, you can still safely require user specified modules. If
202 there are any problems requiring the named module, then we will
203 "croak".
204
205 CGI::Application::Dispatch::PSGI->require_module('MyApp::Module::Name');
206
208 Sometimes it's easiest to explain with an example, so here you go:
209
210 CGI::Application::Dispatch::PSGI->as_psgi(
211 prefix => 'MyApp',
212 args_to_new => {
213 TMPL_PATH => 'myapp/templates'
214 },
215 table => [
216 '' => { app => 'Blog', rm => 'recent'},
217 'posts/:category' => { app => 'Blog', rm => 'posts' },
218 ':app/:rm/:id' => { app => 'Blog' },
219 'date/:year/:month?/:day?' => {
220 app => 'Blog',
221 rm => 'by_date',
222 args_to_new => { TMPL_PATH => "events/" },
223 },
224 ]
225 );
226
227 So first, this call to as_psgi sets the prefix and passes a "TMPL_PATH"
228 into args_to_new. Next it sets the table.
229
230 VOCABULARY
231 Just so we all understand what we're talking about....
232
233 A table is an array where the elements are gouped as pairs (similar to
234 a hash's key-value pairs, but as an array to preserve order). The first
235 element of each pair is called a "rule". The second element in the pair
236 is called the rule's "arg list". Inside a rule there are slashes "/".
237 Anything set of characters between slashes is called a "token".
238
239 URL MATCHING
240 When a URL comes in, Dispatch tries to match it against each rule in
241 the table in the order in which the rules are given. The first one to
242 match wins.
243
244 A rule consists of slashes and tokens. A token can one of the following
245 types:
246
247 literal
248 Any token which does not start with a colon (":") is taken to be a
249 literal string and must appear exactly as-is in the URL in order to
250 match. In the rule
251
252 'posts/:category'
253
254 "posts" is a literal token.
255
256 variable
257 Any token which begins with a colon (":") is a variable token.
258 These are simply wild-card place holders in the rule that will
259 match anything in the URL that isn't a slash. These variables can
260 later be referred to by using the "$self->param" mechanism. In the
261 rule
262
263 'posts/:category'
264
265 ":category" is a variable token. If the URL matched this rule, then
266 you could the value of that token from whithin your application
267 like so:
268
269 my $category = $self->param('category');
270
271 There are some variable tokens which are special. These can be used
272 to further customize the dispatching.
273
274 :app
275 This is the module name of the application. The value of this
276 token will be sent to the translate_module_name method and then
277 prefixed with the prefix if there is one.
278
279 :rm This is the run mode of the application. The value of this
280 token will be the actual name of the run mode used. The run
281 mode can be optional, as noted below. Example:
282
283 /foo/:rm?
284
285 If no run mode is found, it will default to using the
286 start_mode(), just like invoking CGI::Application directly.
287 Both of these URLs would end up dispatching to the start mode
288 associated with /foo:
289
290 /foo/
291 /foo
292
293 optional-variable
294 Any token which begins with a colon (":") and ends with a question
295 mark (<?>) is considered optional. If the rest of the URL matches
296 the rest of the rule, then it doesn't matter whether it contains
297 this token or not. It's best to only include optional-variable
298 tokens at the end of your rule. In the rule
299
300 'date/:year/:month?/:day?'
301
302 ":month?" and ":day?" are optional-variable tokens.
303
304 Just like with variable tokens, optional-variable tokens' values
305 can also be retrieved by the application, if they existed in the
306 URL.
307
308 if( defined $self->param('month') ) {
309 ...
310 }
311
312 wildcard
313 The wildcard token "*" allows for partial matches. The token MUST
314 appear at the end of the rule.
315
316 'posts/list/*'
317
318 By default, the "dispatch_url_remainder" param is set to the
319 remainder of the URL matched by the *. The name of the param can be
320 changed by setting "*" argument in the "ARG LIST".
321
322 'posts/list/*' => { '*' => 'post_list_filter' }
323
324 method
325 You can also dispatch based on HTTP method. This is similar to
326 using auto_rest but offers more fine grained control. You include
327 the method (case insensitive) at the end of the rule and enclose it
328 in square brackets.
329
330 ':app/news[post]' => { rm => 'add_news' },
331 ':app/news[get]' => { rm => 'news' },
332 ':app/news[delete]' => { rm => 'delete_news' },
333
334 The main reason that we don't use regular expressions for dispatch
335 rules is that regular expressions provide no mechanism for named back
336 references, like variable tokens do.
337
338 ARG LIST
339 Each rule can have an accompanying arg-list. This arg list can contain
340 special arguments that override something set higher up in dispatch for
341 this particular URL, or just have additional args passed available in
342 "$self->param()"
343
344 For instance, if you want to override prefix for a specific rule, then
345 you can do so.
346
347 'admin/:app/:rm' => { prefix => 'MyApp::Admin' },
348
350 This section will describe how the application module and run mode are
351 determined from the path if no "DISPATCH TABLE" is present, and what
352 options you have to customize the process. The value for the path to
353 be parsed is retrieved from "$env->{PATH_INFO}".
354
355 Getting the module name
356 To get the name of the application module the path is split on
357 backslahes ("/"). The second element of the returned list (the first
358 is empty) is used to create the application module. So if we have a
359 path of
360
361 /module_name/mode1
362
363 then the string 'module_name' is used. This is passed through the
364 translate_module_name method. Then if there is a "prefix" (and there
365 should always be a prefix) it is added to the beginning of this new
366 module name with a double colon "::" separating the two.
367
368 If you don't like the exact way that this is done, don't fret you do
369 have a couple of options. First, you can specify a "DISPATCH TABLE"
370 which is much more powerful and flexible (in fact this default behavior
371 is actually implemented internally with a dispatch table). Or if you
372 want something a little simpler, you can simply subclass and extend the
373 translate_module_name method.
374
375 Getting the run mode
376 Just like the module name is retrieved from splitting the path on
377 slashes, so is the run mode. Only instead of using the second element
378 of the resulting list, we use the third as the run mode. So, using the
379 same example, if we have a path of
380
381 /module_name/mode2
382
383 Then the string 'mode2' is used as the run mode.
384
386 A CGI::Application object can throw an exception up to
387 "CGI::Application::Dispatch::PSGI" if no error_mode() is implemented or
388 if the error_mode itself throws an exception. In these cases we
389 generally return a generic "500" response, and log some details for the
390 developer with a warning.
391
392 However, we will check to see if the exception thrown is an
393 HTTP::Exception object. If that's the case, we will rethrow it, and you
394 can handle it yourself using something like
395 Plack::Middleware::HTTPExceptions.
396
398 • CGI query strings
399
400 CGI query strings are unaffected by the use of "PATH_INFO" to
401 obtain the module name and run mode. This means that any other
402 modules you use to get access to you query argument (ie, CGI,
403 Apache::Request) should not be affected. But, since the run
404 mode may be determined by CGI::Application::Dispatch::PSGI
405 having a query argument named 'rm' will be ignored by your
406 application module.
407
409 With a dispatch script, you can fairly clean URLS like this:
410
411 /cgi-bin/dispatch.cgi/module_name/run_mode
412
413 However, including "/cgi-bin/dispatch.cgi" in ever URL doesn't add any
414 value to the URL, so it's nice to remove it. This is easily done if you
415 are using the Apache web server with "mod_rewrite" available. Adding
416 the following to a ".htaccess" file would allow you to simply use:
417
418 /module_name/run_mode
419
420 If you have problems with mod_rewrite, turn on debugging to see exactly
421 what's happening:
422
423 RewriteLog /home/project/logs/alpha-rewrite.log
424 RewriteLogLevel 9
425
426 mod_rewrite related code in the dispatch script.
427 This seemed necessary to put in the dispatch script to make mod_rewrite
428 happy. Perhaps it's specific to using "RewriteBase".
429
430 # mod_rewrite alters the PATH_INFO by turning it into a file system path,
431 # so we repair it.
432 $ENV{PATH_INFO} =~ s/^$ENV{DOCUMENT_ROOT}// if defined $ENV{PATH_INFO};
433
434 Simple Apache Example
435 RewriteEngine On
436
437 # You may want to change the base if you are using the dispatcher within a
438 # specific directory.
439 RewriteBase /
440
441 # If an actual file or directory is requested, serve directly
442 RewriteCond %{REQUEST_FILENAME} !-f
443 RewriteCond %{REQUEST_FILENAME} !-d
444
445 # Otherwise, pass everything through to the dispatcher
446 RewriteRule ^(.*)$ /cgi-bin/dispatch.cgi/$1 [L,QSA]
447
448 More complex rewrite: dispatching "/" and multiple developers
449 Here is a more complex example that dispatches "/", which would
450 otherwise be treated as a directory, and also supports multiple
451 developer directories, so "/~mark" has its own separate dispatching
452 system beneath it.
453
454 Note that order matters here! The Location block for "/" needs to come
455 before the user blocks.
456
457 <Location />
458 RewriteEngine On
459 RewriteBase /
460
461 # Run "/" through the dispatcher
462 RewriteRule ^home/project/www/$ /cgi-bin/dispatch.cgi [L,QSA]
463
464 # Don't apply this rule to the users sub directories.
465 RewriteCond %{REQUEST_URI} !^/~.*$
466 # If an actual file or directory is requested, serve directly
467 RewriteCond %{REQUEST_FILENAME} !-f
468 RewriteCond %{REQUEST_FILENAME} !-d
469 # Otherwise, pass everything through to the dispatcher
470 RewriteRule ^(.*)$ /cgi-bin/dispatch.cgi/$1 [L,QSA]
471 </Location>
472
473 <Location /~mark>
474 RewriteEngine On
475 RewriteBase /~mark
476
477 # Run "/" through the dispatcher
478 RewriteRule ^/home/mark/www/$ /~mark/cgi-bin/dispatch.cgi [L,QSA]
479
480 # Otherwise, if an actual file or directory is requested, serve directly
481 RewriteCond %{REQUEST_FILENAME} !-f
482 RewriteCond %{REQUEST_FILENAME} !-d
483
484 # Otherwise, pass everything through to the dispatcher
485 RewriteRule ^(.*)$ /~mark/cgi-bin/dispatch.cgi/$1 [L,QSA]
486
487 # These examples may also be helpful, but are unrelated to dispatching.
488 SetEnv DEVMODE mark
489 SetEnv PERL5LIB /home/mark/perllib:/home/mark/config
490 ErrorDocument 404 /~mark/errdocs/404.html
491 ErrorDocument 500 /~mark/errdocs/500.html
492 </Location>
493
495 While Dispatch tries to be flexible, it won't be able to do everything
496 that people want. Hopefully we've made it flexible enough so that if it
497 doesn't do The Right Thing you can easily subclass it.
498
500 Mark Stosberg <mark@summersault.com>
501
502 Heavily based on CGI::Application::Dispatch, written by Michael Peters
503 <mpeters@plusthree.com> and others
504
506 This module is a part of the larger CGI::Application community. If you
507 have questions or comments about this module then please join us on the
508 cgiapp mailing list by sending a blank message to
509 "cgiapp-subscribe@lists.erlbaum.net". There is also a community wiki
510 located at <http://www.cgi-app.org/>
511
513 A public source code repository for this project is hosted here:
514
515 https://github.com/markstos/CGI--Application--Dispatch
516
518 Since C::A::Dispatch::PSGI will dynamically choose which modules to use
519 as the content generators, it may give someone the ability to execute
520 random modules on your system if those modules can be found in you
521 path. Of course those modules would have to behave like
522 CGI::Application based modules, but that still opens up the door more
523 than most want. This should only be a problem if you don't use a
524 prefix. By using this option you are only allowing Dispatch to pick
525 from a namespace of modules to run.
526
528 Versions 0.2 and earlier of this module injected the "as_psgi" method
529 into CGI::Application::Dispatch, creating a syntax like this:
530
531 ### in your dispatch.psgi:
532 use Your::Application::Dispatch;
533 use CGI::Application::Dispatch::PSGI;
534 Your::Application::Dispatch->as_psgi;
535
536 ### In Your::Application::Dispatch;
537 use base 'CGI::Application::Dispatch::PSGI';
538
539 In the current design, the "as_pgsi" method is directly in this module,
540 so a couple of lines of code need to be changed:
541
542 ### in your dispatch.psgi:
543 use Your::Application::Dispatch;
544 Your::Application::Dispatch->as_psgi;
545
546 ### In Your::Application::Dispatch;
547 use base 'CGI::Application::Dispatch::PSGI';
548
550 dispatch()
551 Use as_psgi() instead.
552
553 Note that the "error_document" key is not supported here. Use the
554 Plack::Middleware::ErrorDocument or another PSGI solution instead.
555
556 dispatch_path()
557 The dispatch_path() method is not supported. The alternative is to
558 reference "$env->{PATH_INFO}" which is available per the PSGI spec.
559
560 handler()
561 This provided an Apache-specific handler. Other PSGI components
562 like Plack::Handler::Apache2 provide Apache handlers now instead.
563
564 _http_method()
565 This method has been eliminated. Check "$env->{REQUEST_METHOD}"
566 directly instead.
567
568 _parse_path()
569 The private _parse_path() method now accepts an additional
570 argument, the PSGI $env hash.
571
572 _run_app()
573 The private _run_app() method now accepts an additional argument,
574 the PSGI $env hash.
575
576 _r()
577 This method has been eliminated. It does not apply in PSGI.
578
580 CGI::Application, Apache::Dispatch
581
583 Copyright Michael Peters and Mark Stosberg 2008-2010, all rights
584 reserved.
585
586 This library is free software; you can redistribute it and/or modify it
587 under the same terms as Perl itself.
588
589
590
591perl v5.38.0 2023-07-C2G0I::Application::Dispatch::PSGI(3pm)