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