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