Fixed MyApp->config->{show_internal_actions}
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
CommitLineData
fc7ec1d9 1package Catalyst;
2
3use strict;
fbcc39ad 4use base 'Catalyst::Base';
5use bytes;
fc7ec1d9 6use UNIVERSAL::require;
a2f2cde9 7use Catalyst::Exception;
fc7ec1d9 8use Catalyst::Log;
fbcc39ad 9use Catalyst::Request;
10use Catalyst::Request::Upload;
11use Catalyst::Response;
812a28c9 12use Catalyst::Utils;
5d9a6d47 13use NEXT;
fbcc39ad 14use Text::ASCIITable;
4f6748f1 15use Path::Class;
fbcc39ad 16use Time::HiRes qw/gettimeofday tv_interval/;
17use URI;
18use Scalar::Util qw/weaken/;
fc7ec1d9 19
66e28e3f 20__PACKAGE__->mk_accessors(
21 qw/counter depth request response state action namespace/
22);
10dd6896 23
fbcc39ad 24# Laziness++
25*comp = \&component;
26*req = \&request;
27*res = \&response;
28
29# For backwards compatibility
30*finalize_output = \&finalize_body;
31
32# For statistics
33our $COUNT = 1;
34our $START = time;
35our $RECURSION = 1000;
36our $DETACH = "catalyst_detach\n";
37
38require Module::Pluggable::Fast;
39
40# Helper script generation
b41ee097 41our $CATALYST_SCRIPT_GEN = 9;
fbcc39ad 42
43__PACKAGE__->mk_classdata($_)
44 for qw/components arguments dispatcher engine log/;
45
bf88a181 46our $VERSION = '5.49_02';
189e2a51 47
fbcc39ad 48sub import {
49 my ( $class, @arguments ) = @_;
50
51 # We have to limit $class to Catalyst to avoid pushing Catalyst upon every
52 # callers @ISA.
53 return unless $class eq 'Catalyst';
54
55 my $caller = caller(0);
56
57 unless ( $caller->isa('Catalyst') ) {
58 no strict 'refs';
59 push @{"$caller\::ISA"}, $class;
60 }
61
62 $caller->arguments( [@arguments] );
63 $caller->setup_home;
64}
fc7ec1d9 65
66=head1 NAME
67
68Catalyst - The Elegant MVC Web Application Framework
69
70=head1 SYNOPSIS
71
72 # use the helper to start a new application
91864987 73 catalyst.pl MyApp
fc7ec1d9 74 cd MyApp
75
76 # add models, views, controllers
ae4e40a7 77 script/myapp_create.pl model Something
78 script/myapp_create.pl view Stuff
79 script/myapp_create.pl controller Yada
fc7ec1d9 80
81 # built in testserver
ae4e40a7 82 script/myapp_server.pl
fc7ec1d9 83
84 # command line interface
ae4e40a7 85 script/myapp_test.pl /yada
fc7ec1d9 86
87
fc7ec1d9 88 use Catalyst;
89
90 use Catalyst qw/My::Module My::OtherModule/;
91
92 use Catalyst '-Debug';
93
94 use Catalyst qw/-Debug -Engine=CGI/;
95
5a8ed4fe 96 sub default : Private { $_[1]->res->output('Hello') } );
97
e3dc9d78 98 sub index : Path('/index.html') {
5a8ed4fe 99 my ( $self, $c ) = @_;
100 $c->res->output('Hello');
064834ea 101 $c->forward('foo');
5a8ed4fe 102 }
103
064834ea 104 sub product : Regex('^product[_]*(\d*).html$') {
5a8ed4fe 105 my ( $self, $c ) = @_;
106 $c->stash->{template} = 'product.tt';
107 $c->stash->{product} = $c->req->snippets->[0];
108 }
fc7ec1d9 109
3803e98f 110See also L<Catalyst::Manual::Intro>
111
fc7ec1d9 112=head1 DESCRIPTION
113
fc7ec1d9 114The key concept of Catalyst is DRY (Don't Repeat Yourself).
115
116See L<Catalyst::Manual> for more documentation.
117
23f9d934 118Catalyst plugins can be loaded by naming them as arguments to the "use Catalyst" statement.
1985c30b 119Omit the C<Catalyst::Plugin::> prefix from the plugin name,
23f9d934 120so C<Catalyst::Plugin::My::Module> becomes C<My::Module>.
fc7ec1d9 121
122 use Catalyst 'My::Module';
123
26e73131 124Special flags like -Debug and -Engine can also be specified as arguments when
23f9d934 125Catalyst is loaded:
fc7ec1d9 126
127 use Catalyst qw/-Debug My::Module/;
128
23f9d934 129The position of plugins and flags in the chain is important, because they are
130loaded in exactly the order that they appear.
fc7ec1d9 131
23f9d934 132The following flags are supported:
133
134=over 4
135
136=item -Debug
137
138enables debug output, i.e.:
fc7ec1d9 139
140 use Catalyst '-Debug';
141
23f9d934 142this is equivalent to:
fc7ec1d9 143
144 use Catalyst;
145 sub debug { 1 }
146
fbcc39ad 147=item -Dispatcher
148
149Force Catalyst to use a specific dispatcher.
150
23f9d934 151=item -Engine
fc7ec1d9 152
153Force Catalyst to use a specific engine.
23f9d934 154Omit the C<Catalyst::Engine::> prefix of the engine name, i.e.:
fc7ec1d9 155
156 use Catalyst '-Engine=CGI';
157
fbcc39ad 158=item -Home
159
160Force Catalyst to use a specific home directory.
161
162=item -Log
163
164Specify log level.
165
23f9d934 166=back
fc7ec1d9 167
23f9d934 168=head1 METHODS
169
170=over 4
171
66e28e3f 172=item $c->action
173
174Accessor for the current action
175
fbcc39ad 176=item $c->comp($name)
177
178=item $c->component($name)
179
180Get a component object by name.
181
182 $c->comp('MyApp::Model::MyModel')->do_stuff;
183
184=cut
185
186sub component {
187 my $c = shift;
188
189 if (@_) {
190
191 my $name = shift;
192
193 my $appclass = ref $c || $c;
194
195 my @names = (
196 $name, "${appclass}::${name}",
197 map { "${appclass}::${_}::${name}" } qw/M V C/
198 );
199
200 foreach my $try (@names) {
201
202 if ( exists $c->components->{$try} ) {
203
204 return $c->components->{$try};
205 }
206 }
207
208 foreach my $component ( keys %{ $c->components } ) {
209
210 return $c->components->{$component} if $component =~ /$name/i;
211 }
212
213 }
214
215 return sort keys %{ $c->components };
216}
217
218=item config
219
220Returns a hashref containing your applications settings.
221
23f9d934 222=item debug
fc7ec1d9 223
224Overload to enable debug messages.
225
226=cut
227
228sub debug { 0 }
229
fbcc39ad 230=item $c->detach( $command [, \@arguments ] )
fc7ec1d9 231
fbcc39ad 232Like C<forward> but doesn't return.
fc7ec1d9 233
234=cut
235
fbcc39ad 236sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) }
237
238=item $c->dispatcher
239
240Contains the dispatcher instance.
241Stringifies to class.
242
243=item $c->forward( $command [, \@arguments ] )
244
245Forward processing to a private action or a method from a class.
246If you define a class without method it will default to process().
247also takes an optional arrayref containing arguments to be passed
248to the new function. $c->req->args will be reset upon returning
249from the function.
250
251 $c->forward('/foo');
252 $c->forward('index');
253 $c->forward(qw/MyApp::Model::CDBI::Foo do_stuff/);
254 $c->forward('MyApp::View::TT');
255
256=cut
257
258sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) }
259
66e28e3f 260=item $c->namespace
261
262Accessor to the namespace of the current action
263
01033d73 264=item $c->path_to(@path)
265
266Merges C<@path> with $c->config->{home} and returns a L<Path::Class> object.
267
268For example:
269
270 $c->path_to( 'db', 'sqlite.db' );
271
272=cut
273
274sub path_to {
275 my ( $c, @path ) = @_;
276 my $path = dir( $c->config->{home}, @path );
277 if ( -d $path ) { return $path }
278 else { return file( $c->config->{home}, @path ) }
279}
280
fbcc39ad 281=item $c->setup
282
283Setup.
284
285 $c->setup;
286
287=cut
288
289sub setup {
0319a12c 290 my ( $class, @arguments ) = @_;
599b5295 291
fbcc39ad 292 unless ( $class->isa('Catalyst') ) {
953b0e15 293
fbcc39ad 294 Catalyst::Exception->throw(
295 message => qq/'$class' does not inherit from Catalyst/ );
1c99e125 296 }
0319a12c 297
fbcc39ad 298 if ( $class->arguments ) {
299 @arguments = ( @arguments, @{ $class->arguments } );
300 }
301
302 # Process options
303 my $flags = {};
304
305 foreach (@arguments) {
306
307 if (/^-Debug$/) {
308 $flags->{log} =
309 ( $flags->{log} ) ? 'debug,' . $flags->{log} : 'debug';
310 }
311 elsif (/^-(\w+)=?(.*)$/) {
312 $flags->{ lc $1 } = $2;
313 }
314 else {
315 push @{ $flags->{plugins} }, $_;
316 }
317 }
318
319 $class->setup_log( delete $flags->{log} );
320 $class->setup_plugins( delete $flags->{plugins} );
321 $class->setup_dispatcher( delete $flags->{dispatcher} );
322 $class->setup_engine( delete $flags->{engine} );
323 $class->setup_home( delete $flags->{home} );
324
325 for my $flag ( sort keys %{$flags} ) {
326
327 if ( my $code = $class->can( 'setup_' . $flag ) ) {
328 &$code( $class, delete $flags->{$flag} );
329 }
330 else {
331 $class->log->warn(qq/Unknown flag "$flag"/);
332 }
333 }
334
335 $class->log->warn( "You are running an old helper script! "
336 . "Please update your scripts by regenerating the "
337 . "application and copying over the new scripts." )
338 if ( $ENV{CATALYST_SCRIPT_GEN}
339 && ( $ENV{CATALYST_SCRIPT_GEN} < $Catalyst::CATALYST_SCRIPT_GEN ) );
340
341 if ( $class->debug ) {
342
343 my @plugins = ();
344
345 {
346 no strict 'refs';
347 @plugins = grep { /^Catalyst::Plugin/ } @{"$class\::ISA"};
348 }
349
350 if (@plugins) {
351 my $t = Text::ASCIITable->new;
352 $t->setOptions( 'hide_HeadRow', 1 );
353 $t->setOptions( 'hide_HeadLine', 1 );
354 $t->setCols('Class');
355 $t->setColWidth( 'Class', 75, 1 );
356 $t->addRow($_) for @plugins;
357 $class->log->debug( "Loaded plugins:\n" . $t->draw );
358 }
359
360 my $dispatcher = $class->dispatcher;
361 my $engine = $class->engine;
362 my $home = $class->config->{home};
363
364 $class->log->debug(qq/Loaded dispatcher "$dispatcher"/);
365 $class->log->debug(qq/Loaded engine "$engine"/);
366
367 $home
368 ? ( -d $home )
369 ? $class->log->debug(qq/Found home "$home"/)
370 : $class->log->debug(qq/Home "$home" doesn't exist/)
371 : $class->log->debug(q/Couldn't find home/);
372 }
373
374 # Call plugins setup
375 {
376 no warnings qw/redefine/;
377 local *setup = sub { };
378 $class->setup;
379 }
380
381 # Initialize our data structure
382 $class->components( {} );
383
384 $class->setup_components;
385
386 if ( $class->debug ) {
387 my $t = Text::ASCIITable->new;
388 $t->setOptions( 'hide_HeadRow', 1 );
389 $t->setOptions( 'hide_HeadLine', 1 );
390 $t->setCols('Class');
391 $t->setColWidth( 'Class', 75, 1 );
392 $t->addRow($_) for sort keys %{ $class->components };
393 $class->log->debug( "Loaded components:\n" . $t->draw )
394 if ( @{ $t->{tbl_rows} } );
395 }
396
397 # Add our self to components, since we are also a component
398 $class->components->{$class} = $class;
399
400 $class->setup_actions;
401
402 if ( $class->debug ) {
403 my $name = $class->config->{name} || 'Application';
404 $class->log->info("$name powered by Catalyst $Catalyst::VERSION");
405 }
406 $class->log->_flush() if $class->log->can('_flush');
407}
408
189e2a51 409=item $c->uri_for($path,[@args])
fbcc39ad 410
411Merges path with $c->request->base for absolute uri's and with
412$c->request->match for relative uri's, then returns a normalized
189e2a51 413L<URI> object. If any args are passed, they are added at the end
414of the path.
fbcc39ad 415
416=cut
417
418sub uri_for {
00e6a2b7 419 my ( $c, $path, @args ) = @_;
fbcc39ad 420 my $base = $c->request->base->clone;
421 my $basepath = $base->path;
422 $basepath =~ s/\/$//;
fdba7a9d 423 $basepath .= '/';
fbcc39ad 424 my $match = $c->request->match;
00e6a2b7 425
189e2a51 426 # massage match, empty if absolute path
fbcc39ad 427 $match =~ s/^\///;
428 $match .= '/' if $match;
429 $match = '' if $path =~ /^\//;
430 $path =~ s/^\///;
00e6a2b7 431
189e2a51 432 # join args with '/', or a blank string
00e6a2b7 433 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
434 return URI->new_abs( URI->new_abs( "$path$args", "$basepath$match" ),
435 $base )->canonical;
fbcc39ad 436}
437
438=item $c->error
439
440=item $c->error($error, ...)
441
442=item $c->error($arrayref)
443
444Returns an arrayref containing error messages.
445
446 my @error = @{ $c->error };
447
448Add a new error.
449
450 $c->error('Something bad happened');
451
00e6a2b7 452Clean errors.
453
454 $c->error(0);
455
fbcc39ad 456=cut
457
458sub error {
459 my $c = shift;
00e6a2b7 460 if ( $_[0] ) {
461 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
462 push @{ $c->{error} }, @$error;
463 }
464 elsif ( defined $_[0] ) { $c->{error} = undef }
465 return $c->{error} || [];
0319a12c 466}
467
468=item $c->engine
469
fbcc39ad 470Contains the engine instance.
471Stringifies to the class.
fc7ec1d9 472
0319a12c 473=item $c->log
474
475Contains the logging object. Unless it is already set Catalyst sets this up with a
476C<Catalyst::Log> object. To use your own log class:
477
478 $c->log( MyLogger->new );
479 $c->log->info("now logging with my own logger!");
480
481Your log class should implement the methods described in the C<Catalyst::Log>
482man page.
483
484=item $c->plugin( $name, $class, @args )
485
486Instant plugins for Catalyst.
487Classdata accessor/mutator will be created, class loaded and instantiated.
488
489 MyApp->plugin( 'prototype', 'HTML::Prototype' );
490
491 $c->prototype->define_javascript_functions;
492
493=cut
494
495sub plugin {
496 my ( $class, $name, $plugin, @args ) = @_;
497 $plugin->require;
498
499 if ( my $error = $UNIVERSAL::require::ERROR ) {
500 Catalyst::Exception->throw(
fbcc39ad 501 message => qq/Couldn't load instant plugin "$plugin", "$error"/ );
0319a12c 502 }
503
504 eval { $plugin->import };
505 $class->mk_classdata($name);
506 my $obj;
507 eval { $obj = $plugin->new(@args) };
508
fbcc39ad 509 if ($@) {
510 Catalyst::Exception->throw( message =>
511 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
0319a12c 512 }
513
514 $class->$name($obj);
515 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
516 if $class->debug;
517}
518
fbcc39ad 519=item $c->request
520
521=item $c->req
522
523Returns a C<Catalyst::Request> object.
524
525 my $req = $c->req;
526
527=item $c->response
528
529=item $c->res
530
531Returns a C<Catalyst::Response> object.
532
533 my $res = $c->res;
534
535=item $c->state
536
537Contains the return value of the last executed action.
538
539=item $c->stash
540
541Returns a hashref containing all your data.
542
fbcc39ad 543 print $c->stash->{foo};
544
23eb3f51 545Keys may be set in the stash by assigning to the hash reference, or by passing
546either a single hash reference or a list of key/value pairs as arguments.
547
548For example:
549
550 $c->stash->{foo} ||= 'yada';
551 $c->stash( { moose => 'majestic', qux => 0 } );
552 $c->stash( bar => 1, gorch => 2 );
553
fbcc39ad 554=cut
555
556sub stash {
557 my $c = shift;
558 if (@_) {
559 my $stash = @_ > 1 ? {@_} : $_[0];
560 while ( my ( $key, $val ) = each %$stash ) {
561 $c->{stash}->{$key} = $val;
562 }
563 }
564 return $c->{stash};
565}
566
2c63fc07 567=item $c->welcome_message
ab2374d3 568
569Returns the Catalyst welcome HTML page.
570
571=cut
572
573sub welcome_message {
bf1f2c60 574 my $c = shift;
575 my $name = $c->config->{name};
576 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
577 my $prefix = Catalyst::Utils::appprefix( ref $c );
ab2374d3 578 return <<"EOF";
579<html>
580 <head>
581 <title>$name on Catalyst $VERSION</title>
582 <style type="text/css">
583 body {
584 text-align: center;
585 padding-left: 50%;
586 color: #000;
587 background-color: #eee;
588 }
589 div#content {
590 width: 640px;
591 margin-left: -320px;
592 margin-top: 10px;
593 margin-bottom: 10px;
594 text-align: left;
595 background-color: #ccc;
596 border: 1px solid #aaa;
597 -moz-border-radius: 10px;
598 }
d84c4dab 599 p, h1, h2 {
ab2374d3 600 margin-left: 20px;
601 margin-right: 20px;
16215972 602 font-family: verdana, tahoma, sans-serif;
ab2374d3 603 }
d84c4dab 604 a {
605 font-family: verdana, tahoma, sans-serif;
606 }
d114e033 607 :link, :visited {
608 text-decoration: none;
609 color: #b00;
610 border-bottom: 1px dotted #bbb;
611 }
612 :link:hover, :visited:hover {
d114e033 613 color: #555;
614 }
ab2374d3 615 div#topbar {
616 margin: 0px;
617 }
3e82a295 618 pre {
3e82a295 619 margin: 10px;
620 padding: 8px;
621 }
ab2374d3 622 div#answers {
623 padding: 8px;
624 margin: 10px;
d114e033 625 background-color: #fff;
ab2374d3 626 border: 1px solid #aaa;
627 -moz-border-radius: 10px;
628 }
629 h1 {
33108eaf 630 font-size: 0.9em;
631 font-weight: normal;
ab2374d3 632 text-align: center;
633 }
634 h2 {
635 font-size: 1.0em;
636 }
637 p {
638 font-size: 0.9em;
639 }
ae7c5252 640 p img {
641 float: right;
642 margin-left: 10px;
643 }
33108eaf 644 b#appname {
645 font-size: 1.6em;
ab2374d3 646 }
647 </style>
648 </head>
649 <body>
650 <div id="content">
651 <div id="topbar">
33108eaf 652 <h1><b id="appname">$name</b> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 653 $VERSION</h1>
ab2374d3 654 </div>
655 <div id="answers">
ae7c5252 656 <p>
f68d720e 657 <img src="$logo"/>
ae7c5252 658 </p>
4b8cb778 659 <p>Welcome to the wonderful world of Catalyst.
f92fd545 660 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
661 framework will make web development something you had
662 never expected it to be: Fun, rewarding and quick.</p>
ab2374d3 663 <h2>What to do now?</h2>
4b8cb778 664 <p>That really depends on what <b>you</b> want to do.
ab2374d3 665 We do, however, provide you with a few starting points.</p>
666 <p>If you want to jump right into web development with Catalyst
5db7f9a1 667 you might want to check out the documentation.</p>
bf1f2c60 668 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
669perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
ab2374d3 670 <h2>What to do next?</h2>
f5681c92 671 <p>Next it's time to write an actual application. Use the
bf1f2c60 672 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
673 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a> and
674 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>,
675 they can save you a lot of work.</p>
676 <pre><code>script/${prefix}_create.pl -help</code></pre>
677 <p>Also, be sure to check out the vast and growing
678 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>,
679 you are likely to find what you need there.
f5681c92 680 </p>
681
82245cc4 682 <h2>Need help?</h2>
f5681c92 683 <p>Catalyst has a very active community. Here are the main places to
684 get in touch with us.</p>
16215972 685 <ul>
686 <li>
2b9a7d76 687 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 688 </li>
689 <li>
690 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
691 </li>
692 <li>
ea7cd80d 693 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 694 </li>
695 </ul>
ab2374d3 696 <h2>In conclusion</h2>
4e7aa2ea 697 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 698 as we enjoyed making it. Please contact us if you have ideas
699 for improvement or other feedback.</p>
ab2374d3 700 </div>
701 </div>
702 </body>
703</html>
704EOF
705}
706
fbcc39ad 707=back
708
709=head1 INTERNAL METHODS
710
711=over 4
712
713=item $c->benchmark($coderef)
714
715Takes a coderef with arguments and returns elapsed time as float.
716
717 my ( $elapsed, $status ) = $c->benchmark( sub { return 1 } );
718 $c->log->info( sprintf "Processing took %f seconds", $elapsed );
719
720=cut
721
722sub benchmark {
723 my $c = shift;
724 my $code = shift;
725 my $time = [gettimeofday];
726 my @return = &$code(@_);
727 my $elapsed = tv_interval $time;
728 return wantarray ? ( $elapsed, @return ) : $elapsed;
729}
730
731=item $c->components
732
733Contains the components.
734
735=item $c->counter
736
737Returns a hashref containing coderefs and execution counts.
738(Needed for deep recursion detection)
739
740=item $c->depth
741
742Returns the actual forward depth.
743
744=item $c->dispatch
745
746Dispatch request to actions.
747
748=cut
749
750sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
751
7f92deef 752=item dump_these
753
754Returns a list of 2-element array references (name, structure) pairs that will
755be dumped on the error page in debug mode.
756
757=cut
758
759sub dump_these {
760 my $c = shift;
761 [ Request => $c->req ], [ Response => $c->res ], [ Stash => $c->stash ],;
762}
763
fbcc39ad 764=item $c->execute($class, $coderef)
765
766Execute a coderef in given class and catch exceptions.
767Errors are available via $c->error.
768
769=cut
770
771sub execute {
772 my ( $c, $class, $code ) = @_;
773 $class = $c->components->{$class} || $class;
774 $c->state(0);
775 my $callsub = ( caller(1) )[3];
776
777 my $action = '';
778 if ( $c->debug ) {
779 $action = "$code";
780 $action = "/$action" unless $action =~ /\-\>/;
781 $c->counter->{"$code"}++;
782
783 if ( $c->counter->{"$code"} > $RECURSION ) {
784 my $error = qq/Deep recursion detected in "$action"/;
785 $c->log->error($error);
786 $c->error($error);
787 $c->state(0);
788 return $c->state;
789 }
790
791 $action = "-> $action" if $callsub =~ /forward$/;
792 }
793 $c->{depth}++;
794 eval {
00e6a2b7 795 if ( $c->debug )
796 {
fbcc39ad 797 my ( $elapsed, @state ) =
798 $c->benchmark( $code, $class, $c, @{ $c->req->args } );
0e7f5826 799 unless ( ( $code->name =~ /^_.*/ )
800 && ( !$c->config->{show_internal_actions} ) )
801 {
802 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
803 }
fbcc39ad 804 $c->state(@state);
805 }
7cfcfd27 806 else {
00e6a2b7 807 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
7cfcfd27 808 }
fbcc39ad 809 };
810 $c->{depth}--;
811
812 if ( my $error = $@ ) {
813
814 if ( $error eq $DETACH ) { die $DETACH if $c->{depth} > 1 }
815 else {
816 unless ( ref $error ) {
817 chomp $error;
818 $error = qq/Caught exception "$error"/;
819 }
820
821 $c->log->error($error);
822 $c->error($error);
823 $c->state(0);
824 }
825 }
826 return $c->state;
827}
828
829=item $c->finalize
830
831Finalize request.
832
833=cut
834
835sub finalize {
836 my $c = shift;
837
838 $c->finalize_uploads;
839
840 # Error
841 if ( $#{ $c->error } >= 0 ) {
842 $c->finalize_error;
843 }
844
845 $c->finalize_headers;
846
847 # HEAD request
848 if ( $c->request->method eq 'HEAD' ) {
849 $c->response->body('');
850 }
851
852 $c->finalize_body;
853
854 return $c->response->status;
855}
856
857=item $c->finalize_body
858
859Finalize body.
860
861=cut
862
863sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
864
865=item $c->finalize_cookies
866
867Finalize cookies.
868
869=cut
870
871sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
872
873=item $c->finalize_error
874
875Finalize error.
876
877=cut
878
879sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
880
881=item $c->finalize_headers
882
883Finalize headers.
884
885=cut
886
887sub finalize_headers {
888 my $c = shift;
889
890 # Check if we already finalized headers
891 return if $c->response->{_finalized_headers};
892
893 # Handle redirects
894 if ( my $location = $c->response->redirect ) {
895 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
896 $c->response->header( Location => $location );
897 }
898
899 # Content-Length
900 if ( $c->response->body && !$c->response->content_length ) {
901 $c->response->content_length( bytes::length( $c->response->body ) );
902 }
903
904 # Errors
905 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
906 $c->response->headers->remove_header("Content-Length");
907 $c->response->body('');
908 }
909
910 $c->finalize_cookies;
911
912 $c->engine->finalize_headers( $c, @_ );
913
914 # Done
915 $c->response->{_finalized_headers} = 1;
916}
917
918=item $c->finalize_output
919
920An alias for finalize_body.
921
922=item $c->finalize_read
923
924Finalize the input after reading is complete.
925
926=cut
927
928sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
929
930=item $c->finalize_uploads
931
932Finalize uploads. Cleans up any temporary files.
933
934=cut
935
936sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
937
a9dc674c 938=item $c->get_action( $action, $namespace )
fbcc39ad 939
940Get an action in a given namespace.
941
942=cut
943
944sub get_action { my $c = shift; $c->dispatcher->get_action( $c, @_ ) }
945
a9dc674c 946=item $c->get_actions( $action, $namespace )
947
948Get all actions of a given name in a namespace and all base namespaces.
949
950=cut
951
952sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
953
fbcc39ad 954=item handle_request( $class, @arguments )
955
956Handles the request.
957
958=cut
959
960sub handle_request {
961 my ( $class, @arguments ) = @_;
962
963 # Always expect worst case!
964 my $status = -1;
965 eval {
966 my @stats = ();
967
968 my $handler = sub {
969 my $c = $class->prepare(@arguments);
970 $c->{stats} = \@stats;
971 $c->dispatch;
972 return $c->finalize;
973 };
974
975 if ( $class->debug ) {
976 my $elapsed;
977 ( $elapsed, $status ) = $class->benchmark($handler);
978 $elapsed = sprintf '%f', $elapsed;
979 my $av = sprintf '%.3f',
980 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
981 my $t = Text::ASCIITable->new;
982 $t->setCols( 'Action', 'Time' );
983 $t->setColWidth( 'Action', 64, 1 );
984 $t->setColWidth( 'Time', 9, 1 );
985
986 for my $stat (@stats) { $t->addRow( $stat->[0], $stat->[1] ) }
987 $class->log->info(
988 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
989 }
990 else { $status = &$handler }
991
992 };
993
994 if ( my $error = $@ ) {
995 chomp $error;
996 $class->log->error(qq/Caught exception in engine "$error"/);
997 }
998
999 $COUNT++;
1000 $class->log->_flush() if $class->log->can('_flush');
1001 return $status;
1002}
1003
1004=item $c->prepare(@arguments)
1005
1006Turns the engine-specific request( Apache, CGI ... )
1007into a Catalyst context .
1008
1009=cut
1010
1011sub prepare {
1012 my ( $class, @arguments ) = @_;
1013
1014 my $c = bless {
1015 counter => {},
1016 depth => 0,
1017 request => Catalyst::Request->new(
1018 {
1019 arguments => [],
1020 body_parameters => {},
1021 cookies => {},
fbcc39ad 1022 headers => HTTP::Headers->new,
1023 parameters => {},
1024 query_parameters => {},
1025 secure => 0,
1026 snippets => [],
1027 uploads => {}
1028 }
1029 ),
1030 response => Catalyst::Response->new(
1031 {
1032 body => '',
1033 cookies => {},
fbcc39ad 1034 headers => HTTP::Headers->new(),
1035 status => 200
1036 }
1037 ),
1038 stash => {},
1039 state => 0
1040 }, $class;
1041
1042 # For on-demand data
1043 $c->request->{_context} = $c;
1044 $c->response->{_context} = $c;
1045 weaken( $c->request->{_context} );
1046 weaken( $c->response->{_context} );
1047
1048 if ( $c->debug ) {
1049 my $secs = time - $START || 1;
1050 my $av = sprintf '%.3f', $COUNT / $secs;
1051 $c->log->debug('**********************************');
1052 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1053 $c->log->debug('**********************************');
1054 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1055 }
1056
1057 $c->prepare_request(@arguments);
1058 $c->prepare_connection;
1059 $c->prepare_query_parameters;
1060 $c->prepare_headers;
1061 $c->prepare_cookies;
1062 $c->prepare_path;
1063
1064 # On-demand parsing
1065 $c->prepare_body unless $c->config->{parse_on_demand};
1066
1067 $c->prepare_action;
1068 my $method = $c->req->method || '';
1069 my $path = $c->req->path || '';
1070 my $address = $c->req->address || '';
1071
1072 $c->log->debug(qq/"$method" request for "$path" from $address/)
1073 if $c->debug;
1074
1075 return $c;
1076}
1077
1078=item $c->prepare_action
1079
1080Prepare action.
1081
1082=cut
1083
1084sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1085
1086=item $c->prepare_body
1087
1088Prepare message body.
1089
1090=cut
1091
1092sub prepare_body {
1093 my $c = shift;
1094
1095 # Do we run for the first time?
1096 return if defined $c->request->{_body};
1097
1098 # Initialize on-demand data
1099 $c->engine->prepare_body( $c, @_ );
1100 $c->prepare_parameters;
1101 $c->prepare_uploads;
1102
1103 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1104 my $t = Text::ASCIITable->new;
1105 $t->setCols( 'Key', 'Value' );
1106 $t->setColWidth( 'Key', 37, 1 );
1107 $t->setColWidth( 'Value', 36, 1 );
1108 $t->alignCol( 'Value', 'right' );
1109 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1110 my $param = $c->req->body_parameters->{$key};
1111 my $value = defined($param) ? $param : '';
1112 $t->addRow( $key,
1113 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1114 }
1115 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1116 }
1117}
1118
4bd82c41 1119=item $c->prepare_body_chunk( $chunk )
1120
1121Prepare a chunk of data before sending it to HTTP::Body.
1122
1123=cut
1124
4f5ebacd 1125sub prepare_body_chunk {
1126 my $c = shift;
4bd82c41 1127 $c->engine->prepare_body_chunk( $c, @_ );
1128}
1129
fbcc39ad 1130=item $c->prepare_body_parameters
1131
1132Prepare body parameters.
1133
1134=cut
1135
1136sub prepare_body_parameters {
1137 my $c = shift;
1138 $c->engine->prepare_body_parameters( $c, @_ );
1139}
1140
1141=item $c->prepare_connection
1142
1143Prepare connection.
1144
1145=cut
1146
1147sub prepare_connection {
1148 my $c = shift;
1149 $c->engine->prepare_connection( $c, @_ );
1150}
1151
1152=item $c->prepare_cookies
1153
1154Prepare cookies.
1155
1156=cut
1157
1158sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1159
1160=item $c->prepare_headers
1161
1162Prepare headers.
1163
1164=cut
1165
1166sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1167
1168=item $c->prepare_parameters
1169
1170Prepare parameters.
1171
1172=cut
1173
1174sub prepare_parameters {
1175 my $c = shift;
1176 $c->prepare_body_parameters;
1177 $c->engine->prepare_parameters( $c, @_ );
1178}
1179
1180=item $c->prepare_path
1181
1182Prepare path and base.
1183
1184=cut
1185
1186sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1187
1188=item $c->prepare_query_parameters
1189
1190Prepare query parameters.
1191
1192=cut
1193
1194sub prepare_query_parameters {
1195 my $c = shift;
1196
1197 $c->engine->prepare_query_parameters( $c, @_ );
1198
1199 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1200 my $t = Text::ASCIITable->new;
1201 $t->setCols( 'Key', 'Value' );
1202 $t->setColWidth( 'Key', 37, 1 );
1203 $t->setColWidth( 'Value', 36, 1 );
1204 $t->alignCol( 'Value', 'right' );
1205 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1206 my $param = $c->req->query_parameters->{$key};
1207 my $value = defined($param) ? $param : '';
1208 $t->addRow( $key,
1209 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1210 }
1211 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1212 }
1213}
1214
1215=item $c->prepare_read
1216
1217Prepare the input for reading.
1218
1219=cut
1220
1221sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1222
1223=item $c->prepare_request
1224
1225Prepare the engine request.
1226
1227=cut
1228
1229sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1230
1231=item $c->prepare_uploads
1232
1233Prepare uploads.
1234
1235=cut
1236
1237sub prepare_uploads {
1238 my $c = shift;
1239
1240 $c->engine->prepare_uploads( $c, @_ );
1241
1242 if ( $c->debug && keys %{ $c->request->uploads } ) {
1243 my $t = Text::ASCIITable->new;
bc2beef5 1244 $t->setCols( 'Key', 'Filename', 'Type', 'Size' );
1245 $t->setColWidth( 'Key', 12, 1 );
1246 $t->setColWidth( 'Filename', 28, 1 );
1247 $t->setColWidth( 'Type', 18, 1 );
fbcc39ad 1248 $t->setColWidth( 'Size', 9, 1 );
1249 $t->alignCol( 'Size', 'left' );
1250 for my $key ( sort keys %{ $c->request->uploads } ) {
1251 my $upload = $c->request->uploads->{$key};
1252 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
bc2beef5 1253 $t->addRow( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1254 }
1255 }
1256 $c->log->debug( "File Uploads are:\n" . $t->draw );
1257 }
1258}
1259
1260=item $c->prepare_write
1261
1262Prepare the output for writing.
1263
1264=cut
1265
1266sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1267
1268=item $c->read( [$maxlength] )
1269
1270Read a chunk of data from the request body. This method is designed to be
1271used in a while loop, reading $maxlength bytes on every call. $maxlength
1272defaults to the size of the request if not specified.
1273
1274You have to set MyApp->config->{parse_on_demand} to use this directly.
1275
1276=cut
1277
1278sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1279
1280=item $c->run
1281
1282Starts the engine.
1283
1284=cut
1285
1286sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1287
1288=item $c->set_action( $action, $code, $namespace, $attrs )
1289
1290Set an action in a given namespace.
1291
1292=cut
1293
1294sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1295
1296=item $c->setup_actions($component)
1297
1298Setup actions for a component.
1299
1300=cut
1301
1302sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1303
1304=item $c->setup_components
1305
1306Setup components.
1307
1308=cut
1309
1310sub setup_components {
1311 my $class = shift;
1312
1313 my $callback = sub {
1314 my ( $component, $context ) = @_;
1315
1316 unless ( $component->isa('Catalyst::Base') ) {
1317 return $component;
1318 }
1319
1320 my $suffix = Catalyst::Utils::class2classsuffix($component);
1321 my $config = $class->config->{$suffix} || {};
1322
1323 my $instance;
1324
1325 eval { $instance = $component->new( $context, $config ); };
1326
1327 if ( my $error = $@ ) {
1328
1329 chomp $error;
1330
1331 Catalyst::Exception->throw( message =>
1332 qq/Couldn't instantiate component "$component", "$error"/ );
1333 }
1334
1335 Catalyst::Exception->throw( message =>
1336qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1337 )
1338 unless ref $instance;
1339 return $instance;
1340 };
1341
1342 eval {
1343 Module::Pluggable::Fast->import(
1344 name => '_catalyst_components',
1345 search => [
1346 "$class\::Controller", "$class\::C",
1347 "$class\::Model", "$class\::M",
1348 "$class\::View", "$class\::V"
1349 ],
1350 callback => $callback
1351 );
1352 };
1353
1354 if ( my $error = $@ ) {
1355
1356 chomp $error;
1357
1358 Catalyst::Exception->throw(
1359 message => qq/Couldn't load components "$error"/ );
1360 }
1361
1362 for my $component ( $class->_catalyst_components($class) ) {
1363 $class->components->{ ref $component || $component } = $component;
1364 }
1365}
1366
1367=item $c->setup_dispatcher
1368
1369=cut
1370
1371sub setup_dispatcher {
1372 my ( $class, $dispatcher ) = @_;
1373
1374 if ($dispatcher) {
1375 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1376 }
1377
1378 if ( $ENV{CATALYST_DISPATCHER} ) {
1379 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1380 }
1381
1382 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1383 $dispatcher =
1384 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1385 }
1386
1387 unless ($dispatcher) {
1388 $dispatcher = 'Catalyst::Dispatcher';
1389 }
1390
1391 $dispatcher->require;
1392
1393 if ($@) {
1394 Catalyst::Exception->throw(
1395 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1396 }
1397
1398 # dispatcher instance
1399 $class->dispatcher( $dispatcher->new );
1400}
1401
1402=item $c->setup_engine
1403
1404=cut
1405
1406sub setup_engine {
1407 my ( $class, $engine ) = @_;
1408
1409 if ($engine) {
1410 $engine = 'Catalyst::Engine::' . $engine;
1411 }
1412
1413 if ( $ENV{CATALYST_ENGINE} ) {
1414 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1415 }
1416
1417 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1418 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1419 }
1420
1421 if ( !$engine && $ENV{MOD_PERL} ) {
1422
1423 # create the apache method
1424 {
1425 no strict 'refs';
1426 *{"$class\::apache"} = sub { shift->engine->apache };
1427 }
1428
1429 my ( $software, $version ) =
1430 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1431
1432 $version =~ s/_//g;
1433 $version =~ s/(\.[^.]+)\./$1/g;
1434
1435 if ( $software eq 'mod_perl' ) {
1436
1437 if ( $version >= 1.99922 ) {
1438 $engine = 'Catalyst::Engine::Apache2::MP20';
1439 }
1440
1441 elsif ( $version >= 1.9901 ) {
1442 $engine = 'Catalyst::Engine::Apache2::MP19';
1443 }
1444
1445 elsif ( $version >= 1.24 ) {
1446 $engine = 'Catalyst::Engine::Apache::MP13';
1447 }
1448
1449 else {
1450 Catalyst::Exception->throw( message =>
1451 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1452 }
1453
1454 # install the correct mod_perl handler
1455 if ( $version >= 1.9901 ) {
1456 *handler = sub : method {
1457 shift->handle_request(@_);
1458 };
1459 }
1460 else {
1461 *handler = sub ($$) { shift->handle_request(@_) };
1462 }
1463
1464 }
1465
1466 elsif ( $software eq 'Zeus-Perl' ) {
1467 $engine = 'Catalyst::Engine::Zeus';
1468 }
1469
1470 else {
1471 Catalyst::Exception->throw(
1472 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1473 }
1474 }
1475
1476 unless ($engine) {
1477 $engine = 'Catalyst::Engine::CGI';
1478 }
1479
1480 $engine->require;
1481
1482 if ($@) {
1483 Catalyst::Exception->throw( message =>
1484qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1485 );
1486 }
0e7f5826 1487
d54484bf 1488 # check for old engines that are no longer compatible
1489 my $old_engine;
0e7f5826 1490 if ( $engine->isa('Catalyst::Engine::Apache')
1491 && !Catalyst::Engine::Apache->VERSION )
d54484bf 1492 {
1493 $old_engine = 1;
1494 }
0e7f5826 1495
d54484bf 1496 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 1497 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 1498 {
1499 $old_engine = 1;
1500 }
0e7f5826 1501
1502 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1503 && $engine->VERSION eq '0.01' )
d54484bf 1504 {
1505 $old_engine = 1;
1506 }
0e7f5826 1507
1508 elsif ($engine->isa('Catalyst::Engine::Zeus')
1509 && $engine->VERSION eq '0.01' )
d54484bf 1510 {
1511 $old_engine = 1;
1512 }
fbcc39ad 1513
d54484bf 1514 if ($old_engine) {
1515 Catalyst::Exception->throw( message =>
0e7f5826 1516 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 1517 );
1518 }
0e7f5826 1519
fbcc39ad 1520 # engine instance
1521 $class->engine( $engine->new );
1522}
1523
1524=item $c->setup_home
1525
1526=cut
1527
1528sub setup_home {
1529 my ( $class, $home ) = @_;
1530
1531 if ( $ENV{CATALYST_HOME} ) {
1532 $home = $ENV{CATALYST_HOME};
1533 }
1534
1535 if ( $ENV{ uc($class) . '_HOME' } ) {
1536 $home = $ENV{ uc($class) . '_HOME' };
1537 }
1538
1539 unless ($home) {
1540 $home = Catalyst::Utils::home($class);
1541 }
1542
1543 if ($home) {
1544 $class->config->{home} ||= $home;
1545 $class->config->{root} ||= dir($home)->subdir('root');
1546 }
1547}
1548
1549=item $c->setup_log
1550
1551=cut
1552
1553sub setup_log {
1554 my ( $class, $debug ) = @_;
1555
1556 unless ( $class->log ) {
1557 $class->log( Catalyst::Log->new );
1558 }
1559
1560 if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($class) . '_DEBUG' } || $debug ) {
1561 no strict 'refs';
1562 *{"$class\::debug"} = sub { 1 };
1563 $class->log->debug('Debug messages enabled');
1564 }
1565}
1566
1567=item $c->setup_plugins
1568
1569=cut
1570
1571sub setup_plugins {
1572 my ( $class, $plugins ) = @_;
1573
1574 $plugins ||= [];
1575 for my $plugin ( reverse @$plugins ) {
1576
1577 $plugin = "Catalyst::Plugin::$plugin";
1578
1579 $plugin->require;
1580
1581 if ($@) {
1582 Catalyst::Exception->throw(
1583 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1584 }
1585
1586 {
1587 no strict 'refs';
1588 unshift @{"$class\::ISA"}, $plugin;
1589 }
1590 }
1591}
1592
1593=item $c->write( $data )
1594
1595Writes $data to the output stream. When using this method directly, you will
1596need to manually set the Content-Length header to the length of your output
1597data, if known.
1598
1599=cut
1600
4f5ebacd 1601sub write {
1602 my $c = shift;
1603
1604 # Finalize headers if someone manually writes output
1605 $c->finalize_headers;
1606
1607 return $c->engine->write( $c, @_ );
1608}
fbcc39ad 1609
bf88a181 1610=item version
1611
1612Returns the Catalyst version number. mostly useful for powered by messages
1613in template systems.
1614
1615=cut
1616
1617sub version { return $Catalyst::VERSION }
1618
23f9d934 1619=back
1620
b0bb11ec 1621=head1 INTERNAL ACTIONS
1622
1623Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1624C<_ACTION> and C<_END>, these are by default not shown in the private
1625action table.
1626
1627But you can deactivate this with a config parameter.
1628
1629 MyApp->config->{show_internal_actions} = 1;
1630
d2ee9760 1631=head1 CASE SENSITIVITY
1632
1633By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1634C</foo/bar>.
1635
1636But you can activate case sensitivity with a config parameter.
1637
1638 MyApp->config->{case_sensitive} = 1;
1639
fbcc39ad 1640So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1641
1642=head1 ON-DEMAND PARSER
1643
1644The request body is usually parsed at the beginning of a request,
1645but if you want to handle input yourself or speed things up a bit
1646you can enable on-demand parsing with a config parameter.
1647
1648 MyApp->config->{parse_on_demand} = 1;
1649
1650=head1 PROXY SUPPORT
1651
1652Many production servers operate using the common double-server approach, with
1653a lightweight frontend web server passing requests to a larger backend
1654server. An application running on the backend server must deal with two
1655problems: the remote user always appears to be '127.0.0.1' and the server's
1656hostname will appear to be 'localhost' regardless of the virtual host the
1657user connected through.
1658
1659Catalyst will automatically detect this situation when you are running both
1660the frontend and backend servers on the same machine. The following changes
1661are made to the request.
1662
1663 $c->req->address is set to the user's real IP address, as read from the
1664 HTTP_X_FORWARDED_FOR header.
1665
1666 The host value for $c->req->base and $c->req->uri is set to the real host,
1667 as read from the HTTP_X_FORWARDED_HOST header.
1668
1669Obviously, your web server must support these 2 headers for this to work.
1670
1671In a more complex server farm environment where you may have your frontend
1672proxy server(s) on different machines, you will need to set a configuration
1673option to tell Catalyst to read the proxied data from the headers.
1674
1675 MyApp->config->{using_frontend_proxy} = 1;
1676
1677If you do not wish to use the proxy support at all, you may set:
d1a31ac6 1678
fbcc39ad 1679 MyApp->config->{ignore_frontend_proxy} = 1;
1680
1681=head1 THREAD SAFETY
1682
1683Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1684and the standalone forking HTTP server on Windows. We believe the Catalyst
1685core to be thread-safe.
1686
1687If you plan to operate in a threaded environment, remember that all other
1688modules you are using must also be thread-safe. Some modules, most notably
1689DBD::SQLite, are not thread-safe.
d1a31ac6 1690
3cb1db8c 1691=head1 SUPPORT
1692
1693IRC:
1694
1695 Join #catalyst on irc.perl.org.
1696
1697Mailing-Lists:
1698
1699 http://lists.rawmode.org/mailman/listinfo/catalyst
1700 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 1701
432d507d 1702Web:
1703
1704 http://catalyst.perl.org
1705
fc7ec1d9 1706=head1 SEE ALSO
1707
61b1e958 1708=over 4
1709
1710=item L<Catalyst::Manual> - The Catalyst Manual
1711
1712=item L<Catalyst::Engine> - Core Engine
1713
1714=item L<Catalyst::Log> - The Log Class.
1715
1716=item L<Catalyst::Request> - The Request Object
1717
1718=item L<Catalyst::Response> - The Response Object
1719
1720=item L<Catalyst::Test> - The test suite.
1721
1722=back
fc7ec1d9 1723
15f0b5b7 1724=head1 CREDITS
fc7ec1d9 1725
15f0b5b7 1726Andy Grundman
1727
fbcc39ad 1728Andy Wardley
1729
33108eaf 1730Andreas Marienborg
1731
f4a57de4 1732Andrew Bramble
1733
15f0b5b7 1734Andrew Ford
1735
1736Andrew Ruthven
1737
fbcc39ad 1738Arthur Bergman
1739
15f0b5b7 1740Autrijus Tang
1741
1742Christian Hansen
1743
1744Christopher Hicks
1745
1746Dan Sully
1747
1748Danijel Milicevic
1749
1750David Naughton
1751
1752Gary Ashton Jones
1753
1754Geoff Richards
1755
1756Jesse Sheidlower
1757
fbcc39ad 1758Jesse Vincent
1759
15f0b5b7 1760Jody Belka
1761
1762Johan Lindstrom
1763
1764Juan Camacho
1765
1766Leon Brocard
1767
1768Marcus Ramberg
1769
1770Matt S Trout
1771
71c3bcc3 1772Robert Sedlacek
1773
a727119f 1774Sam Vilain
1775
15f0b5b7 1776Tatsuhiko Miyagawa
fc7ec1d9 1777
51f0308d 1778Ulf Edvinsson
1779
bdcb95ef 1780Yuval Kogman
1781
51f0308d 1782=head1 AUTHOR
1783
1784Sebastian Riedel, C<sri@oook.de>
1785
fc7ec1d9 1786=head1 LICENSE
1787
9ce5ab63 1788This library is free software, you can redistribute it and/or modify it under
41ca9ba7 1789the same terms as Perl itself.
fc7ec1d9 1790
1791=cut
1792
17931;