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