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