Updated Intro.pod
[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             $c->error($error);
866             $c->state(0);
867         }
868     }
869     return $c->state;
870 }
871
872 =item $c->finalize
873
874 Finalize request.
875
876 =cut
877
878 sub finalize {
879     my $c = shift;
880
881     for my $error ( @{ $c->error } ) {
882         $c->log->error($error);
883     }
884
885     $c->finalize_uploads;
886
887     # Error
888     if ( $#{ $c->error } >= 0 ) {
889         $c->finalize_error;
890     }
891
892     $c->finalize_headers;
893
894     # HEAD request
895     if ( $c->request->method eq 'HEAD' ) {
896         $c->response->body('');
897     }
898
899     $c->finalize_body;
900
901     return $c->response->status;
902 }
903
904 =item $c->finalize_body
905
906 Finalize body.
907
908 =cut
909
910 sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
911
912 =item $c->finalize_cookies
913
914 Finalize cookies.
915
916 =cut
917
918 sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
919
920 =item $c->finalize_error
921
922 Finalize error.
923
924 =cut
925
926 sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
927
928 =item $c->finalize_headers
929
930 Finalize headers.
931
932 =cut
933
934 sub finalize_headers {
935     my $c = shift;
936
937     # Check if we already finalized headers
938     return if $c->response->{_finalized_headers};
939
940     # Handle redirects
941     if ( my $location = $c->response->redirect ) {
942         $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
943         $c->response->header( Location => $location );
944     }
945
946     # Content-Length
947     if ( $c->response->body && !$c->response->content_length ) {
948         $c->response->content_length( bytes::length( $c->response->body ) );
949     }
950
951     # Errors
952     if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
953         $c->response->headers->remove_header("Content-Length");
954         $c->response->body('');
955     }
956
957     $c->finalize_cookies;
958
959     $c->engine->finalize_headers( $c, @_ );
960
961     # Done
962     $c->response->{_finalized_headers} = 1;
963 }
964
965 =item $c->finalize_output
966
967 An alias for finalize_body.
968
969 =item $c->finalize_read
970
971 Finalize the input after reading is complete.
972
973 =cut
974
975 sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
976
977 =item $c->finalize_uploads
978
979 Finalize uploads.  Cleans up any temporary files.
980
981 =cut
982
983 sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
984
985 =item $c->get_action( $action, $namespace )
986
987 Get an action in a given namespace.
988
989 =cut
990
991 sub get_action { my $c = shift; $c->dispatcher->get_action( @_ ) }
992
993 =item $c->get_actions( $action, $namespace )
994
995 Get all actions of a given name in a namespace and all base namespaces.
996
997 =cut
998
999 sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
1000
1001 =item handle_request( $class, @arguments )
1002
1003 Handles the request.
1004
1005 =cut
1006
1007 sub handle_request {
1008     my ( $class, @arguments ) = @_;
1009
1010     # Always expect worst case!
1011     my $status = -1;
1012     eval {
1013         my @stats = ();
1014
1015         my $handler = sub {
1016             my $c = $class->prepare(@arguments);
1017             $c->{stats} = \@stats;
1018             $c->dispatch;
1019             return $c->finalize;
1020         };
1021
1022         if ( $class->debug ) {
1023             my $elapsed;
1024             ( $elapsed, $status ) = $class->benchmark($handler);
1025             $elapsed = sprintf '%f', $elapsed;
1026             my $av = sprintf '%.3f',
1027               ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
1028             my $t = Text::SimpleTable->new( [ 64, 'Action' ], [ 9, 'Time' ] );
1029
1030             for my $stat (@stats) { $t->row( $stat->[0], $stat->[1] ) }
1031             $class->log->info(
1032                 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
1033         }
1034         else { $status = &$handler }
1035
1036     };
1037
1038     if ( my $error = $@ ) {
1039         chomp $error;
1040         $class->log->error(qq/Caught exception in engine "$error"/);
1041     }
1042
1043     $COUNT++;
1044     $class->log->_flush() if $class->log->can('_flush');
1045     return $status;
1046 }
1047
1048 =item $c->prepare(@arguments)
1049
1050 Turns the engine-specific request( Apache, CGI ... )
1051 into a Catalyst context .
1052
1053 =cut
1054
1055 sub prepare {
1056     my ( $class, @arguments ) = @_;
1057
1058     my $c = bless {
1059         counter => {},
1060         depth   => 0,
1061         request => Catalyst::Request->new(
1062             {
1063                 arguments        => [],
1064                 body_parameters  => {},
1065                 cookies          => {},
1066                 headers          => HTTP::Headers->new,
1067                 parameters       => {},
1068                 query_parameters => {},
1069                 secure           => 0,
1070                 snippets         => [],
1071                 uploads          => {}
1072             }
1073         ),
1074         response => Catalyst::Response->new(
1075             {
1076                 body    => '',
1077                 cookies => {},
1078                 headers => HTTP::Headers->new(),
1079                 status  => 200
1080             }
1081         ),
1082         stash => {},
1083         state => 0
1084     }, $class;
1085
1086     # For on-demand data
1087     $c->request->{_context}  = $c;
1088     $c->response->{_context} = $c;
1089     weaken( $c->request->{_context} );
1090     weaken( $c->response->{_context} );
1091
1092     if ( $c->debug ) {
1093         my $secs = time - $START || 1;
1094         my $av = sprintf '%.3f', $COUNT / $secs;
1095         $c->log->debug('**********************************');
1096         $c->log->debug("* Request $COUNT ($av/s) [$$]");
1097         $c->log->debug('**********************************');
1098         $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1099     }
1100
1101     $c->prepare_request(@arguments);
1102     $c->prepare_connection;
1103     $c->prepare_query_parameters;
1104     $c->prepare_headers;
1105     $c->prepare_cookies;
1106     $c->prepare_path;
1107
1108     # On-demand parsing
1109     $c->prepare_body unless $c->config->{parse_on_demand};
1110
1111     $c->prepare_action;
1112     my $method  = $c->req->method  || '';
1113     my $path    = $c->req->path    || '';
1114     my $address = $c->req->address || '';
1115
1116     $c->log->debug(qq/"$method" request for "$path" from $address/)
1117       if $c->debug;
1118
1119     return $c;
1120 }
1121
1122 =item $c->prepare_action
1123
1124 Prepare action.
1125
1126 =cut
1127
1128 sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1129
1130 =item $c->prepare_body
1131
1132 Prepare message body.
1133
1134 =cut
1135
1136 sub prepare_body {
1137     my $c = shift;
1138
1139     # Do we run for the first time?
1140     return if defined $c->request->{_body};
1141
1142     # Initialize on-demand data
1143     $c->engine->prepare_body( $c, @_ );
1144     $c->prepare_parameters;
1145     $c->prepare_uploads;
1146
1147     if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1148         my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1149         for my $key ( sort keys %{ $c->req->body_parameters } ) {
1150             my $param = $c->req->body_parameters->{$key};
1151             my $value = defined($param) ? $param : '';
1152             $t->row( $key,
1153                 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1154         }
1155         $c->log->debug( "Body Parameters are:\n" . $t->draw );
1156     }
1157 }
1158
1159 =item $c->prepare_body_chunk( $chunk )
1160
1161 Prepare a chunk of data before sending it to HTTP::Body.
1162
1163 =cut
1164
1165 sub prepare_body_chunk {
1166     my $c = shift;
1167     $c->engine->prepare_body_chunk( $c, @_ );
1168 }
1169
1170 =item $c->prepare_body_parameters
1171
1172 Prepare body parameters.
1173
1174 =cut
1175
1176 sub prepare_body_parameters {
1177     my $c = shift;
1178     $c->engine->prepare_body_parameters( $c, @_ );
1179 }
1180
1181 =item $c->prepare_connection
1182
1183 Prepare connection.
1184
1185 =cut
1186
1187 sub prepare_connection {
1188     my $c = shift;
1189     $c->engine->prepare_connection( $c, @_ );
1190 }
1191
1192 =item $c->prepare_cookies
1193
1194 Prepare cookies.
1195
1196 =cut
1197
1198 sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1199
1200 =item $c->prepare_headers
1201
1202 Prepare headers.
1203
1204 =cut
1205
1206 sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1207
1208 =item $c->prepare_parameters
1209
1210 Prepare parameters.
1211
1212 =cut
1213
1214 sub prepare_parameters {
1215     my $c = shift;
1216     $c->prepare_body_parameters;
1217     $c->engine->prepare_parameters( $c, @_ );
1218 }
1219
1220 =item $c->prepare_path
1221
1222 Prepare path and base.
1223
1224 =cut
1225
1226 sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1227
1228 =item $c->prepare_query_parameters
1229
1230 Prepare query parameters.
1231
1232 =cut
1233
1234 sub prepare_query_parameters {
1235     my $c = shift;
1236
1237     $c->engine->prepare_query_parameters( $c, @_ );
1238
1239     if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1240         my $t = Text::SimpleTable->new( [ 37, 'Key' ], [ 36, 'Value' ] );
1241         for my $key ( sort keys %{ $c->req->query_parameters } ) {
1242             my $param = $c->req->query_parameters->{$key};
1243             my $value = defined($param) ? $param : '';
1244             $t->row( $key,
1245                 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1246         }
1247         $c->log->debug( "Query Parameters are:\n" . $t->draw );
1248     }
1249 }
1250
1251 =item $c->prepare_read
1252
1253 Prepare the input for reading.
1254
1255 =cut
1256
1257 sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1258
1259 =item $c->prepare_request
1260
1261 Prepare the engine request.
1262
1263 =cut
1264
1265 sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1266
1267 =item $c->prepare_uploads
1268
1269 Prepare uploads.
1270
1271 =cut
1272
1273 sub prepare_uploads {
1274     my $c = shift;
1275
1276     $c->engine->prepare_uploads( $c, @_ );
1277
1278     if ( $c->debug && keys %{ $c->request->uploads } ) {
1279         my $t = Text::SimpleTable->new(
1280             [ 12, 'Key' ],
1281             [ 28, 'Filename' ],
1282             [ 18, 'Type' ],
1283             [ 9,  'Size' ]
1284         );
1285         for my $key ( sort keys %{ $c->request->uploads } ) {
1286             my $upload = $c->request->uploads->{$key};
1287             for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
1288                 $t->row( $key, $u->filename, $u->type, $u->size );
1289             }
1290         }
1291         $c->log->debug( "File Uploads are:\n" . $t->draw );
1292     }
1293 }
1294
1295 =item $c->prepare_write
1296
1297 Prepare the output for writing.
1298
1299 =cut
1300
1301 sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1302
1303 =item $c->read( [$maxlength] )
1304
1305 Read a chunk of data from the request body.  This method is designed to be
1306 used in a while loop, reading $maxlength bytes on every call.  $maxlength
1307 defaults to the size of the request if not specified.
1308
1309 You have to set MyApp->config->{parse_on_demand} to use this directly.
1310
1311 =cut
1312
1313 sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1314
1315 =item $c->run
1316
1317 Starts the engine.
1318
1319 =cut
1320
1321 sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1322
1323 =item $c->set_action( $action, $code, $namespace, $attrs )
1324
1325 Set an action in a given namespace.
1326
1327 =cut
1328
1329 sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1330
1331 =item $c->setup_actions($component)
1332
1333 Setup actions for a component.
1334
1335 =cut
1336
1337 sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1338
1339 =item $c->setup_components
1340
1341 Setup components.
1342
1343 =cut
1344
1345 sub setup_components {
1346     my $class = shift;
1347
1348     my $callback = sub {
1349         my ( $component, $context ) = @_;
1350
1351         unless ( $component->isa('Catalyst::Component') ) {
1352             return $component;
1353         }
1354
1355         my $suffix = Catalyst::Utils::class2classsuffix($class);
1356         my $config = $class->config->{$suffix} || {};
1357
1358         my $instance;
1359
1360         eval { $instance = $component->new( $context, $config ); };
1361
1362         if ( my $error = $@ ) {
1363
1364             chomp $error;
1365
1366             Catalyst::Exception->throw( message =>
1367                   qq/Couldn't instantiate component "$component", "$error"/ );
1368         }
1369
1370         Catalyst::Exception->throw( message =>
1371 qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1372           )
1373           unless ref $instance;
1374         return $instance;
1375     };
1376
1377     eval {
1378         Module::Pluggable::Fast->import(
1379             name   => '_catalyst_components',
1380             search => [
1381                 "$class\::Controller", "$class\::C",
1382                 "$class\::Model",      "$class\::M",
1383                 "$class\::View",       "$class\::V"
1384             ],
1385             callback => $callback
1386         );
1387     };
1388
1389     if ( my $error = $@ ) {
1390
1391         chomp $error;
1392
1393         Catalyst::Exception->throw(
1394             message => qq/Couldn't load components "$error"/ );
1395     }
1396
1397     for my $component ( $class->_catalyst_components($class) ) {
1398         $class->components->{ ref $component || $component } = $component;
1399     }
1400 }
1401
1402 =item $c->setup_dispatcher
1403
1404 =cut
1405
1406 sub setup_dispatcher {
1407     my ( $class, $dispatcher ) = @_;
1408
1409     if ($dispatcher) {
1410         $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1411     }
1412
1413     if ( $ENV{CATALYST_DISPATCHER} ) {
1414         $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1415     }
1416
1417     if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1418         $dispatcher =
1419           'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1420     }
1421
1422     unless ($dispatcher) {
1423         $dispatcher = 'Catalyst::Dispatcher';
1424     }
1425
1426     $dispatcher->require;
1427
1428     if ($@) {
1429         Catalyst::Exception->throw(
1430             message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1431     }
1432
1433     # dispatcher instance
1434     $class->dispatcher( $dispatcher->new );
1435 }
1436
1437 =item $c->setup_engine
1438
1439 =cut
1440
1441 sub setup_engine {
1442     my ( $class, $engine ) = @_;
1443
1444     if ($engine) {
1445         $engine = 'Catalyst::Engine::' . $engine;
1446     }
1447
1448     if ( $ENV{CATALYST_ENGINE} ) {
1449         $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1450     }
1451
1452     if ( $ENV{ uc($class) . '_ENGINE' } ) {
1453         $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1454     }
1455
1456     if ( !$engine && $ENV{MOD_PERL} ) {
1457
1458         # create the apache method
1459         {
1460             no strict 'refs';
1461             *{"$class\::apache"} = sub { shift->engine->apache };
1462         }
1463
1464         my ( $software, $version ) =
1465           $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1466
1467         $version =~ s/_//g;
1468         $version =~ s/(\.[^.]+)\./$1/g;
1469
1470         if ( $software eq 'mod_perl' ) {
1471
1472             if ( $version >= 1.99922 ) {
1473                 $engine = 'Catalyst::Engine::Apache2::MP20';
1474             }
1475
1476             elsif ( $version >= 1.9901 ) {
1477                 $engine = 'Catalyst::Engine::Apache2::MP19';
1478             }
1479
1480             elsif ( $version >= 1.24 ) {
1481                 $engine = 'Catalyst::Engine::Apache::MP13';
1482             }
1483
1484             else {
1485                 Catalyst::Exception->throw( message =>
1486                       qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1487             }
1488
1489             # install the correct mod_perl handler
1490             if ( $version >= 1.9901 ) {
1491                 *handler = sub  : method {
1492                     shift->handle_request(@_);
1493                 };
1494             }
1495             else {
1496                 *handler = sub ($$) { shift->handle_request(@_) };
1497             }
1498
1499         }
1500
1501         elsif ( $software eq 'Zeus-Perl' ) {
1502             $engine = 'Catalyst::Engine::Zeus';
1503         }
1504
1505         else {
1506             Catalyst::Exception->throw(
1507                 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1508         }
1509     }
1510
1511     unless ($engine) {
1512         $engine = 'Catalyst::Engine::CGI';
1513     }
1514
1515     $engine->require;
1516
1517     if ($@) {
1518         Catalyst::Exception->throw( message =>
1519 qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1520         );
1521     }
1522
1523     # check for old engines that are no longer compatible
1524     my $old_engine;
1525     if ( $engine->isa('Catalyst::Engine::Apache')
1526         && !Catalyst::Engine::Apache->VERSION )
1527     {
1528         $old_engine = 1;
1529     }
1530
1531     elsif ( $engine->isa('Catalyst::Engine::Server::Base')
1532         && Catalyst::Engine::Server->VERSION le '0.02' )
1533     {
1534         $old_engine = 1;
1535     }
1536
1537     elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1538         && $engine->VERSION eq '0.01' )
1539     {
1540         $old_engine = 1;
1541     }
1542
1543     elsif ($engine->isa('Catalyst::Engine::Zeus')
1544         && $engine->VERSION eq '0.01' )
1545     {
1546         $old_engine = 1;
1547     }
1548
1549     if ($old_engine) {
1550         Catalyst::Exception->throw( message =>
1551               qq/Engine "$engine" is not supported by this version of Catalyst/
1552         );
1553     }
1554
1555     # engine instance
1556     $class->engine( $engine->new );
1557 }
1558
1559 =item $c->setup_home
1560
1561 =cut
1562
1563 sub setup_home {
1564     my ( $class, $home ) = @_;
1565
1566     if ( $ENV{CATALYST_HOME} ) {
1567         $home = $ENV{CATALYST_HOME};
1568     }
1569
1570     if ( $ENV{ uc($class) . '_HOME' } ) {
1571         $home = $ENV{ uc($class) . '_HOME' };
1572     }
1573
1574     unless ($home) {
1575         $home = Catalyst::Utils::home($class);
1576     }
1577
1578     if ($home) {
1579         $class->config->{home} ||= $home;
1580         $class->config->{root} ||= dir($home)->subdir('root');
1581     }
1582 }
1583
1584 =item $c->setup_log
1585
1586 =cut
1587
1588 sub setup_log {
1589     my ( $class, $debug ) = @_;
1590
1591     unless ( $class->log ) {
1592         $class->log( Catalyst::Log->new );
1593     }
1594
1595     my $app_flag = Catalyst::Utils::class2env($class) . '_DEBUG';
1596
1597     if (
1598           ( defined( $ENV{CATALYST_DEBUG} ) || defined( $ENV{$app_flag} ) )
1599         ? ( $ENV{CATALYST_DEBUG} || $ENV{$app_flag} )
1600         : $debug
1601       )
1602     {
1603         no strict 'refs';
1604         *{"$class\::debug"} = sub { 1 };
1605         $class->log->debug('Debug messages enabled');
1606     }
1607 }
1608
1609 =item $c->setup_plugins
1610
1611 =cut
1612
1613 sub setup_plugins {
1614     my ( $class, $plugins ) = @_;
1615
1616     $plugins ||= [];
1617     for my $plugin ( reverse @$plugins ) {
1618
1619         $plugin = "Catalyst::Plugin::$plugin";
1620
1621         $plugin->require;
1622
1623         if ($@) {
1624             Catalyst::Exception->throw(
1625                 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1626         }
1627
1628         {
1629             no strict 'refs';
1630             unshift @{"$class\::ISA"}, $plugin;
1631         }
1632     }
1633 }
1634
1635 =item $c->write( $data )
1636
1637 Writes $data to the output stream.  When using this method directly, you will
1638 need to manually set the Content-Length header to the length of your output
1639 data, if known.
1640
1641 =cut
1642
1643 sub write {
1644     my $c = shift;
1645
1646     # Finalize headers if someone manually writes output
1647     $c->finalize_headers;
1648
1649     return $c->engine->write( $c, @_ );
1650 }
1651
1652 =item version
1653
1654 Returns the Catalyst version number. mostly useful for powered by messages
1655 in template systems.
1656
1657 =cut
1658
1659 sub version { return $Catalyst::VERSION }
1660
1661 =back
1662
1663 =head1 INTERNAL ACTIONS
1664
1665 Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1666 C<_ACTION> and C<_END>, these are by default not shown in the private
1667 action table.
1668
1669 But you can deactivate this with a config parameter.
1670
1671     MyApp->config->{show_internal_actions} = 1;
1672
1673 =head1 CASE SENSITIVITY
1674
1675 By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1676 C</foo/bar>.
1677
1678 But you can activate case sensitivity with a config parameter.
1679
1680     MyApp->config->{case_sensitive} = 1;
1681
1682 So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1683
1684 =head1 ON-DEMAND PARSER
1685
1686 The request body is usually parsed at the beginning of a request,
1687 but if you want to handle input yourself or speed things up a bit
1688 you can enable on-demand parsing with a config parameter.
1689
1690     MyApp->config->{parse_on_demand} = 1;
1691     
1692 =head1 PROXY SUPPORT
1693
1694 Many production servers operate using the common double-server approach, with
1695 a lightweight frontend web server passing requests to a larger backend
1696 server.  An application running on the backend server must deal with two
1697 problems: the remote user always appears to be '127.0.0.1' and the server's
1698 hostname will appear to be 'localhost' regardless of the virtual host the
1699 user connected through.
1700
1701 Catalyst will automatically detect this situation when you are running both
1702 the frontend and backend servers on the same machine.  The following changes
1703 are made to the request.
1704
1705     $c->req->address is set to the user's real IP address, as read from the
1706     HTTP_X_FORWARDED_FOR header.
1707     
1708     The host value for $c->req->base and $c->req->uri is set to the real host,
1709     as read from the HTTP_X_FORWARDED_HOST header.
1710
1711 Obviously, your web server must support these 2 headers for this to work.
1712
1713 In a more complex server farm environment where you may have your frontend
1714 proxy server(s) on different machines, you will need to set a configuration
1715 option to tell Catalyst to read the proxied data from the headers.
1716
1717     MyApp->config->{using_frontend_proxy} = 1;
1718     
1719 If you do not wish to use the proxy support at all, you may set:
1720
1721     MyApp->config->{ignore_frontend_proxy} = 1;
1722
1723 =head1 THREAD SAFETY
1724
1725 Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1726 and the standalone forking HTTP server on Windows.  We believe the Catalyst
1727 core to be thread-safe.
1728
1729 If you plan to operate in a threaded environment, remember that all other
1730 modules you are using must also be thread-safe.  Some modules, most notably
1731 DBD::SQLite, are not thread-safe.
1732
1733 =head1 SUPPORT
1734
1735 IRC:
1736
1737     Join #catalyst on irc.perl.org.
1738
1739 Mailing-Lists:
1740
1741     http://lists.rawmode.org/mailman/listinfo/catalyst
1742     http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1743
1744 Web:
1745
1746     http://catalyst.perl.org
1747
1748 =head1 SEE ALSO
1749
1750 =over 4
1751
1752 =item L<Catalyst::Manual> - The Catalyst Manual
1753
1754 =item L<Catalyst::Engine> - Core Engine
1755
1756 =item L<Catalyst::Log> - The Log Class.
1757
1758 =item L<Catalyst::Request> - The Request Object
1759
1760 =item L<Catalyst::Response> - The Response Object
1761
1762 =item L<Catalyst::Test> - The test suite.
1763
1764 =back
1765
1766 =head1 CREDITS
1767
1768 Andy Grundman
1769
1770 Andy Wardley
1771
1772 Andreas Marienborg
1773
1774 Andrew Bramble
1775
1776 Andrew Ford
1777
1778 Andrew Ruthven
1779
1780 Arthur Bergman
1781
1782 Autrijus Tang
1783
1784 Brian Cassidy
1785
1786 Christian Hansen
1787
1788 Christopher Hicks
1789
1790 Dan Sully
1791
1792 Danijel Milicevic
1793
1794 David Naughton
1795
1796 Gary Ashton Jones
1797
1798 Geoff Richards
1799
1800 Jesse Sheidlower
1801
1802 Jesse Vincent
1803
1804 Jody Belka
1805
1806 Johan Lindstrom
1807
1808 Juan Camacho
1809
1810 Leon Brocard
1811
1812 Marcus Ramberg
1813
1814 Matt S Trout
1815
1816 Robert Sedlacek
1817
1818 Sam Vilain
1819
1820 Sascha Kiefer
1821
1822 Tatsuhiko Miyagawa
1823
1824 Ulf Edvinsson
1825
1826 Yuval Kogman
1827
1828 =head1 AUTHOR
1829
1830 Sebastian Riedel, C<sri@oook.de>
1831
1832 =head1 LICENSE
1833
1834 This library is free software, you can redistribute it and/or modify it under
1835 the same terms as Perl itself.
1836
1837 =cut
1838
1839 1;