Fixed typo
[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;
6e0c45c9 429 $path ||= '';
fbcc39ad 430 $match = '' if $path =~ /^\//;
431 $path =~ s/^\///;
00e6a2b7 432
189e2a51 433 # join args with '/', or a blank string
00e6a2b7 434 my $args = ( scalar @args ? '/' . join( '/', @args ) : '' );
435 return URI->new_abs( URI->new_abs( "$path$args", "$basepath$match" ),
436 $base )->canonical;
fbcc39ad 437}
438
439=item $c->error
440
441=item $c->error($error, ...)
442
443=item $c->error($arrayref)
444
445Returns an arrayref containing error messages.
446
447 my @error = @{ $c->error };
448
449Add a new error.
450
451 $c->error('Something bad happened');
452
00e6a2b7 453Clean errors.
454
455 $c->error(0);
456
fbcc39ad 457=cut
458
459sub error {
460 my $c = shift;
00e6a2b7 461 if ( $_[0] ) {
462 my $error = ref $_[0] eq 'ARRAY' ? $_[0] : [@_];
463 push @{ $c->{error} }, @$error;
464 }
465 elsif ( defined $_[0] ) { $c->{error} = undef }
466 return $c->{error} || [];
0319a12c 467}
468
469=item $c->engine
470
fbcc39ad 471Contains the engine instance.
472Stringifies to the class.
fc7ec1d9 473
0319a12c 474=item $c->log
475
476Contains the logging object. Unless it is already set Catalyst sets this up with a
477C<Catalyst::Log> object. To use your own log class:
478
479 $c->log( MyLogger->new );
480 $c->log->info("now logging with my own logger!");
481
482Your log class should implement the methods described in the C<Catalyst::Log>
483man page.
484
485=item $c->plugin( $name, $class, @args )
486
487Instant plugins for Catalyst.
488Classdata accessor/mutator will be created, class loaded and instantiated.
489
490 MyApp->plugin( 'prototype', 'HTML::Prototype' );
491
492 $c->prototype->define_javascript_functions;
493
494=cut
495
496sub plugin {
497 my ( $class, $name, $plugin, @args ) = @_;
498 $plugin->require;
499
500 if ( my $error = $UNIVERSAL::require::ERROR ) {
501 Catalyst::Exception->throw(
fbcc39ad 502 message => qq/Couldn't load instant plugin "$plugin", "$error"/ );
0319a12c 503 }
504
505 eval { $plugin->import };
506 $class->mk_classdata($name);
507 my $obj;
508 eval { $obj = $plugin->new(@args) };
509
fbcc39ad 510 if ($@) {
511 Catalyst::Exception->throw( message =>
512 qq/Couldn't instantiate instant plugin "$plugin", "$@"/ );
0319a12c 513 }
514
515 $class->$name($obj);
516 $class->log->debug(qq/Initialized instant plugin "$plugin" as "$name"/)
517 if $class->debug;
518}
519
fbcc39ad 520=item $c->request
521
522=item $c->req
523
524Returns a C<Catalyst::Request> object.
525
526 my $req = $c->req;
527
528=item $c->response
529
530=item $c->res
531
532Returns a C<Catalyst::Response> object.
533
534 my $res = $c->res;
535
536=item $c->state
537
538Contains the return value of the last executed action.
539
540=item $c->stash
541
542Returns a hashref containing all your data.
543
fbcc39ad 544 print $c->stash->{foo};
545
23eb3f51 546Keys may be set in the stash by assigning to the hash reference, or by passing
547either a single hash reference or a list of key/value pairs as arguments.
548
549For example:
550
551 $c->stash->{foo} ||= 'yada';
552 $c->stash( { moose => 'majestic', qux => 0 } );
553 $c->stash( bar => 1, gorch => 2 );
554
fbcc39ad 555=cut
556
557sub stash {
558 my $c = shift;
559 if (@_) {
560 my $stash = @_ > 1 ? {@_} : $_[0];
561 while ( my ( $key, $val ) = each %$stash ) {
562 $c->{stash}->{$key} = $val;
563 }
564 }
565 return $c->{stash};
566}
567
2c63fc07 568=item $c->welcome_message
ab2374d3 569
570Returns the Catalyst welcome HTML page.
571
572=cut
573
574sub welcome_message {
bf1f2c60 575 my $c = shift;
576 my $name = $c->config->{name};
577 my $logo = $c->uri_for('/static/images/catalyst_logo.png');
578 my $prefix = Catalyst::Utils::appprefix( ref $c );
ab2374d3 579 return <<"EOF";
580<html>
581 <head>
582 <title>$name on Catalyst $VERSION</title>
583 <style type="text/css">
584 body {
585 text-align: center;
586 padding-left: 50%;
587 color: #000;
588 background-color: #eee;
589 }
590 div#content {
591 width: 640px;
592 margin-left: -320px;
593 margin-top: 10px;
594 margin-bottom: 10px;
595 text-align: left;
596 background-color: #ccc;
597 border: 1px solid #aaa;
598 -moz-border-radius: 10px;
599 }
d84c4dab 600 p, h1, h2 {
ab2374d3 601 margin-left: 20px;
602 margin-right: 20px;
16215972 603 font-family: verdana, tahoma, sans-serif;
ab2374d3 604 }
d84c4dab 605 a {
606 font-family: verdana, tahoma, sans-serif;
607 }
d114e033 608 :link, :visited {
609 text-decoration: none;
610 color: #b00;
611 border-bottom: 1px dotted #bbb;
612 }
613 :link:hover, :visited:hover {
d114e033 614 color: #555;
615 }
ab2374d3 616 div#topbar {
617 margin: 0px;
618 }
3e82a295 619 pre {
3e82a295 620 margin: 10px;
621 padding: 8px;
622 }
ab2374d3 623 div#answers {
624 padding: 8px;
625 margin: 10px;
d114e033 626 background-color: #fff;
ab2374d3 627 border: 1px solid #aaa;
628 -moz-border-radius: 10px;
629 }
630 h1 {
33108eaf 631 font-size: 0.9em;
632 font-weight: normal;
ab2374d3 633 text-align: center;
634 }
635 h2 {
636 font-size: 1.0em;
637 }
638 p {
639 font-size: 0.9em;
640 }
ae7c5252 641 p img {
642 float: right;
643 margin-left: 10px;
644 }
33108eaf 645 b#appname {
646 font-size: 1.6em;
ab2374d3 647 }
648 </style>
649 </head>
650 <body>
651 <div id="content">
652 <div id="topbar">
33108eaf 653 <h1><b id="appname">$name</b> on <a href="http://catalyst.perl.org">Catalyst</a>
d84c4dab 654 $VERSION</h1>
ab2374d3 655 </div>
656 <div id="answers">
ae7c5252 657 <p>
f68d720e 658 <img src="$logo"/>
ae7c5252 659 </p>
4b8cb778 660 <p>Welcome to the wonderful world of Catalyst.
f92fd545 661 This <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>
662 framework will make web development something you had
663 never expected it to be: Fun, rewarding and quick.</p>
ab2374d3 664 <h2>What to do now?</h2>
4b8cb778 665 <p>That really depends on what <b>you</b> want to do.
ab2374d3 666 We do, however, provide you with a few starting points.</p>
667 <p>If you want to jump right into web development with Catalyst
5db7f9a1 668 you might want to check out the documentation.</p>
bf1f2c60 669 <pre><code>perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual/Intro.pod">Catalyst::Manual::Intro</a>
670perldoc <a href="http://cpansearch.perl.org/dist/Catalyst/lib/Catalyst/Manual.pod">Catalyst::Manual</a></code></pre>
ab2374d3 671 <h2>What to do next?</h2>
f5681c92 672 <p>Next it's time to write an actual application. Use the
bf1f2c60 673 helper scripts to generate <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AController%3A%3A&mode=all">controllers</a>,
674 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AModel%3A%3A&mode=all">models</a> and
675 <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3AView%3A%3A&mode=all">views</a>,
676 they can save you a lot of work.</p>
677 <pre><code>script/${prefix}_create.pl -help</code></pre>
678 <p>Also, be sure to check out the vast and growing
679 collection of <a href="http://cpansearch.perl.org/search?query=Catalyst%3A%3APlugin%3A%3A&mode=all">plugins for Catalyst on CPAN</a>,
680 you are likely to find what you need there.
f5681c92 681 </p>
682
82245cc4 683 <h2>Need help?</h2>
f5681c92 684 <p>Catalyst has a very active community. Here are the main places to
685 get in touch with us.</p>
16215972 686 <ul>
687 <li>
2b9a7d76 688 <a href="http://dev.catalyst.perl.org">Wiki</a>
16215972 689 </li>
690 <li>
691 <a href="http://lists.rawmode.org/mailman/listinfo/catalyst">Mailing-List</a>
692 </li>
693 <li>
ea7cd80d 694 <a href="irc://irc.perl.org/catalyst">IRC channel #catalyst on irc.perl.org</a>
16215972 695 </li>
696 </ul>
ab2374d3 697 <h2>In conclusion</h2>
4e7aa2ea 698 <p>The Catalyst team hopes you will enjoy using Catalyst as much
f5681c92 699 as we enjoyed making it. Please contact us if you have ideas
700 for improvement or other feedback.</p>
ab2374d3 701 </div>
702 </div>
703 </body>
704</html>
705EOF
706}
707
fbcc39ad 708=back
709
710=head1 INTERNAL METHODS
711
712=over 4
713
714=item $c->benchmark($coderef)
715
716Takes a coderef with arguments and returns elapsed time as float.
717
718 my ( $elapsed, $status ) = $c->benchmark( sub { return 1 } );
719 $c->log->info( sprintf "Processing took %f seconds", $elapsed );
720
721=cut
722
723sub benchmark {
724 my $c = shift;
725 my $code = shift;
726 my $time = [gettimeofday];
727 my @return = &$code(@_);
728 my $elapsed = tv_interval $time;
729 return wantarray ? ( $elapsed, @return ) : $elapsed;
730}
731
732=item $c->components
733
734Contains the components.
735
736=item $c->counter
737
738Returns a hashref containing coderefs and execution counts.
739(Needed for deep recursion detection)
740
741=item $c->depth
742
743Returns the actual forward depth.
744
745=item $c->dispatch
746
747Dispatch request to actions.
748
749=cut
750
751sub dispatch { my $c = shift; $c->dispatcher->dispatch( $c, @_ ) }
752
7f92deef 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 } );
0e7f5826 800 unless ( ( $code->name =~ /^_.*/ )
801 && ( !$c->config->{show_internal_actions} ) )
802 {
803 push @{ $c->{stats} }, [ $action, sprintf( '%fs', $elapsed ) ];
804 }
fbcc39ad 805 $c->state(@state);
806 }
7cfcfd27 807 else {
00e6a2b7 808 $c->state( &$code( $class, $c, @{ $c->req->args } ) || 0 );
7cfcfd27 809 }
fbcc39ad 810 };
811 $c->{depth}--;
812
813 if ( my $error = $@ ) {
814
815 if ( $error eq $DETACH ) { die $DETACH if $c->{depth} > 1 }
816 else {
817 unless ( ref $error ) {
818 chomp $error;
819 $error = qq/Caught exception "$error"/;
820 }
821
822 $c->log->error($error);
823 $c->error($error);
824 $c->state(0);
825 }
826 }
827 return $c->state;
828}
829
830=item $c->finalize
831
832Finalize request.
833
834=cut
835
836sub finalize {
837 my $c = shift;
838
839 $c->finalize_uploads;
840
841 # Error
842 if ( $#{ $c->error } >= 0 ) {
843 $c->finalize_error;
844 }
845
846 $c->finalize_headers;
847
848 # HEAD request
849 if ( $c->request->method eq 'HEAD' ) {
850 $c->response->body('');
851 }
852
853 $c->finalize_body;
854
855 return $c->response->status;
856}
857
858=item $c->finalize_body
859
860Finalize body.
861
862=cut
863
864sub finalize_body { my $c = shift; $c->engine->finalize_body( $c, @_ ) }
865
866=item $c->finalize_cookies
867
868Finalize cookies.
869
870=cut
871
872sub finalize_cookies { my $c = shift; $c->engine->finalize_cookies( $c, @_ ) }
873
874=item $c->finalize_error
875
876Finalize error.
877
878=cut
879
880sub finalize_error { my $c = shift; $c->engine->finalize_error( $c, @_ ) }
881
882=item $c->finalize_headers
883
884Finalize headers.
885
886=cut
887
888sub finalize_headers {
889 my $c = shift;
890
891 # Check if we already finalized headers
892 return if $c->response->{_finalized_headers};
893
894 # Handle redirects
895 if ( my $location = $c->response->redirect ) {
896 $c->log->debug(qq/Redirecting to "$location"/) if $c->debug;
897 $c->response->header( Location => $location );
898 }
899
900 # Content-Length
901 if ( $c->response->body && !$c->response->content_length ) {
902 $c->response->content_length( bytes::length( $c->response->body ) );
903 }
904
905 # Errors
906 if ( $c->response->status =~ /^(1\d\d|[23]04)$/ ) {
907 $c->response->headers->remove_header("Content-Length");
908 $c->response->body('');
909 }
910
911 $c->finalize_cookies;
912
913 $c->engine->finalize_headers( $c, @_ );
914
915 # Done
916 $c->response->{_finalized_headers} = 1;
917}
918
919=item $c->finalize_output
920
921An alias for finalize_body.
922
923=item $c->finalize_read
924
925Finalize the input after reading is complete.
926
927=cut
928
929sub finalize_read { my $c = shift; $c->engine->finalize_read( $c, @_ ) }
930
931=item $c->finalize_uploads
932
933Finalize uploads. Cleans up any temporary files.
934
935=cut
936
937sub finalize_uploads { my $c = shift; $c->engine->finalize_uploads( $c, @_ ) }
938
a9dc674c 939=item $c->get_action( $action, $namespace )
fbcc39ad 940
941Get an action in a given namespace.
942
943=cut
944
945sub get_action { my $c = shift; $c->dispatcher->get_action( $c, @_ ) }
946
a9dc674c 947=item $c->get_actions( $action, $namespace )
948
949Get all actions of a given name in a namespace and all base namespaces.
950
951=cut
952
953sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
954
fbcc39ad 955=item handle_request( $class, @arguments )
956
957Handles the request.
958
959=cut
960
961sub handle_request {
962 my ( $class, @arguments ) = @_;
963
964 # Always expect worst case!
965 my $status = -1;
966 eval {
967 my @stats = ();
968
969 my $handler = sub {
970 my $c = $class->prepare(@arguments);
971 $c->{stats} = \@stats;
972 $c->dispatch;
973 return $c->finalize;
974 };
975
976 if ( $class->debug ) {
977 my $elapsed;
978 ( $elapsed, $status ) = $class->benchmark($handler);
979 $elapsed = sprintf '%f', $elapsed;
980 my $av = sprintf '%.3f',
981 ( $elapsed == 0 ? '??' : ( 1 / $elapsed ) );
982 my $t = Text::ASCIITable->new;
983 $t->setCols( 'Action', 'Time' );
984 $t->setColWidth( 'Action', 64, 1 );
985 $t->setColWidth( 'Time', 9, 1 );
986
987 for my $stat (@stats) { $t->addRow( $stat->[0], $stat->[1] ) }
988 $class->log->info(
989 "Request took ${elapsed}s ($av/s)\n" . $t->draw );
990 }
991 else { $status = &$handler }
992
993 };
994
995 if ( my $error = $@ ) {
996 chomp $error;
997 $class->log->error(qq/Caught exception in engine "$error"/);
998 }
999
1000 $COUNT++;
1001 $class->log->_flush() if $class->log->can('_flush');
1002 return $status;
1003}
1004
1005=item $c->prepare(@arguments)
1006
1007Turns the engine-specific request( Apache, CGI ... )
1008into a Catalyst context .
1009
1010=cut
1011
1012sub prepare {
1013 my ( $class, @arguments ) = @_;
1014
1015 my $c = bless {
1016 counter => {},
1017 depth => 0,
1018 request => Catalyst::Request->new(
1019 {
1020 arguments => [],
1021 body_parameters => {},
1022 cookies => {},
fbcc39ad 1023 headers => HTTP::Headers->new,
1024 parameters => {},
1025 query_parameters => {},
1026 secure => 0,
1027 snippets => [],
1028 uploads => {}
1029 }
1030 ),
1031 response => Catalyst::Response->new(
1032 {
1033 body => '',
1034 cookies => {},
fbcc39ad 1035 headers => HTTP::Headers->new(),
1036 status => 200
1037 }
1038 ),
1039 stash => {},
1040 state => 0
1041 }, $class;
1042
1043 # For on-demand data
1044 $c->request->{_context} = $c;
1045 $c->response->{_context} = $c;
1046 weaken( $c->request->{_context} );
1047 weaken( $c->response->{_context} );
1048
1049 if ( $c->debug ) {
1050 my $secs = time - $START || 1;
1051 my $av = sprintf '%.3f', $COUNT / $secs;
1052 $c->log->debug('**********************************');
1053 $c->log->debug("* Request $COUNT ($av/s) [$$]");
1054 $c->log->debug('**********************************');
1055 $c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
1056 }
1057
1058 $c->prepare_request(@arguments);
1059 $c->prepare_connection;
1060 $c->prepare_query_parameters;
1061 $c->prepare_headers;
1062 $c->prepare_cookies;
1063 $c->prepare_path;
1064
1065 # On-demand parsing
1066 $c->prepare_body unless $c->config->{parse_on_demand};
1067
1068 $c->prepare_action;
1069 my $method = $c->req->method || '';
1070 my $path = $c->req->path || '';
1071 my $address = $c->req->address || '';
1072
1073 $c->log->debug(qq/"$method" request for "$path" from $address/)
1074 if $c->debug;
1075
1076 return $c;
1077}
1078
1079=item $c->prepare_action
1080
1081Prepare action.
1082
1083=cut
1084
1085sub prepare_action { my $c = shift; $c->dispatcher->prepare_action( $c, @_ ) }
1086
1087=item $c->prepare_body
1088
1089Prepare message body.
1090
1091=cut
1092
1093sub prepare_body {
1094 my $c = shift;
1095
1096 # Do we run for the first time?
1097 return if defined $c->request->{_body};
1098
1099 # Initialize on-demand data
1100 $c->engine->prepare_body( $c, @_ );
1101 $c->prepare_parameters;
1102 $c->prepare_uploads;
1103
1104 if ( $c->debug && keys %{ $c->req->body_parameters } ) {
1105 my $t = Text::ASCIITable->new;
1106 $t->setCols( 'Key', 'Value' );
1107 $t->setColWidth( 'Key', 37, 1 );
1108 $t->setColWidth( 'Value', 36, 1 );
1109 $t->alignCol( 'Value', 'right' );
1110 for my $key ( sort keys %{ $c->req->body_parameters } ) {
1111 my $param = $c->req->body_parameters->{$key};
1112 my $value = defined($param) ? $param : '';
1113 $t->addRow( $key,
1114 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1115 }
1116 $c->log->debug( "Body Parameters are:\n" . $t->draw );
1117 }
1118}
1119
4bd82c41 1120=item $c->prepare_body_chunk( $chunk )
1121
1122Prepare a chunk of data before sending it to HTTP::Body.
1123
1124=cut
1125
4f5ebacd 1126sub prepare_body_chunk {
1127 my $c = shift;
4bd82c41 1128 $c->engine->prepare_body_chunk( $c, @_ );
1129}
1130
fbcc39ad 1131=item $c->prepare_body_parameters
1132
1133Prepare body parameters.
1134
1135=cut
1136
1137sub prepare_body_parameters {
1138 my $c = shift;
1139 $c->engine->prepare_body_parameters( $c, @_ );
1140}
1141
1142=item $c->prepare_connection
1143
1144Prepare connection.
1145
1146=cut
1147
1148sub prepare_connection {
1149 my $c = shift;
1150 $c->engine->prepare_connection( $c, @_ );
1151}
1152
1153=item $c->prepare_cookies
1154
1155Prepare cookies.
1156
1157=cut
1158
1159sub prepare_cookies { my $c = shift; $c->engine->prepare_cookies( $c, @_ ) }
1160
1161=item $c->prepare_headers
1162
1163Prepare headers.
1164
1165=cut
1166
1167sub prepare_headers { my $c = shift; $c->engine->prepare_headers( $c, @_ ) }
1168
1169=item $c->prepare_parameters
1170
1171Prepare parameters.
1172
1173=cut
1174
1175sub prepare_parameters {
1176 my $c = shift;
1177 $c->prepare_body_parameters;
1178 $c->engine->prepare_parameters( $c, @_ );
1179}
1180
1181=item $c->prepare_path
1182
1183Prepare path and base.
1184
1185=cut
1186
1187sub prepare_path { my $c = shift; $c->engine->prepare_path( $c, @_ ) }
1188
1189=item $c->prepare_query_parameters
1190
1191Prepare query parameters.
1192
1193=cut
1194
1195sub prepare_query_parameters {
1196 my $c = shift;
1197
1198 $c->engine->prepare_query_parameters( $c, @_ );
1199
1200 if ( $c->debug && keys %{ $c->request->query_parameters } ) {
1201 my $t = Text::ASCIITable->new;
1202 $t->setCols( 'Key', 'Value' );
1203 $t->setColWidth( 'Key', 37, 1 );
1204 $t->setColWidth( 'Value', 36, 1 );
1205 $t->alignCol( 'Value', 'right' );
1206 for my $key ( sort keys %{ $c->req->query_parameters } ) {
1207 my $param = $c->req->query_parameters->{$key};
1208 my $value = defined($param) ? $param : '';
1209 $t->addRow( $key,
1210 ref $value eq 'ARRAY' ? ( join ', ', @$value ) : $value );
1211 }
1212 $c->log->debug( "Query Parameters are:\n" . $t->draw );
1213 }
1214}
1215
1216=item $c->prepare_read
1217
1218Prepare the input for reading.
1219
1220=cut
1221
1222sub prepare_read { my $c = shift; $c->engine->prepare_read( $c, @_ ) }
1223
1224=item $c->prepare_request
1225
1226Prepare the engine request.
1227
1228=cut
1229
1230sub prepare_request { my $c = shift; $c->engine->prepare_request( $c, @_ ) }
1231
1232=item $c->prepare_uploads
1233
1234Prepare uploads.
1235
1236=cut
1237
1238sub prepare_uploads {
1239 my $c = shift;
1240
1241 $c->engine->prepare_uploads( $c, @_ );
1242
1243 if ( $c->debug && keys %{ $c->request->uploads } ) {
1244 my $t = Text::ASCIITable->new;
bc2beef5 1245 $t->setCols( 'Key', 'Filename', 'Type', 'Size' );
1246 $t->setColWidth( 'Key', 12, 1 );
1247 $t->setColWidth( 'Filename', 28, 1 );
1248 $t->setColWidth( 'Type', 18, 1 );
fbcc39ad 1249 $t->setColWidth( 'Size', 9, 1 );
1250 $t->alignCol( 'Size', 'left' );
1251 for my $key ( sort keys %{ $c->request->uploads } ) {
1252 my $upload = $c->request->uploads->{$key};
1253 for my $u ( ref $upload eq 'ARRAY' ? @{$upload} : ($upload) ) {
bc2beef5 1254 $t->addRow( $key, $u->filename, $u->type, $u->size );
fbcc39ad 1255 }
1256 }
1257 $c->log->debug( "File Uploads are:\n" . $t->draw );
1258 }
1259}
1260
1261=item $c->prepare_write
1262
1263Prepare the output for writing.
1264
1265=cut
1266
1267sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
1268
1269=item $c->read( [$maxlength] )
1270
1271Read a chunk of data from the request body. This method is designed to be
1272used in a while loop, reading $maxlength bytes on every call. $maxlength
1273defaults to the size of the request if not specified.
1274
1275You have to set MyApp->config->{parse_on_demand} to use this directly.
1276
1277=cut
1278
1279sub read { my $c = shift; return $c->engine->read( $c, @_ ) }
1280
1281=item $c->run
1282
1283Starts the engine.
1284
1285=cut
1286
1287sub run { my $c = shift; return $c->engine->run( $c, @_ ) }
1288
1289=item $c->set_action( $action, $code, $namespace, $attrs )
1290
1291Set an action in a given namespace.
1292
1293=cut
1294
1295sub set_action { my $c = shift; $c->dispatcher->set_action( $c, @_ ) }
1296
1297=item $c->setup_actions($component)
1298
1299Setup actions for a component.
1300
1301=cut
1302
1303sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) }
1304
1305=item $c->setup_components
1306
1307Setup components.
1308
1309=cut
1310
1311sub setup_components {
1312 my $class = shift;
1313
1314 my $callback = sub {
1315 my ( $component, $context ) = @_;
1316
1317 unless ( $component->isa('Catalyst::Base') ) {
1318 return $component;
1319 }
1320
1321 my $suffix = Catalyst::Utils::class2classsuffix($component);
1322 my $config = $class->config->{$suffix} || {};
1323
1324 my $instance;
1325
1326 eval { $instance = $component->new( $context, $config ); };
1327
1328 if ( my $error = $@ ) {
1329
1330 chomp $error;
1331
1332 Catalyst::Exception->throw( message =>
1333 qq/Couldn't instantiate component "$component", "$error"/ );
1334 }
1335
1336 Catalyst::Exception->throw( message =>
1337qq/Couldn't instantiate component "$component", "new() didn't return a object"/
1338 )
1339 unless ref $instance;
1340 return $instance;
1341 };
1342
1343 eval {
1344 Module::Pluggable::Fast->import(
1345 name => '_catalyst_components',
1346 search => [
1347 "$class\::Controller", "$class\::C",
1348 "$class\::Model", "$class\::M",
1349 "$class\::View", "$class\::V"
1350 ],
1351 callback => $callback
1352 );
1353 };
1354
1355 if ( my $error = $@ ) {
1356
1357 chomp $error;
1358
1359 Catalyst::Exception->throw(
1360 message => qq/Couldn't load components "$error"/ );
1361 }
1362
1363 for my $component ( $class->_catalyst_components($class) ) {
1364 $class->components->{ ref $component || $component } = $component;
1365 }
1366}
1367
1368=item $c->setup_dispatcher
1369
1370=cut
1371
1372sub setup_dispatcher {
1373 my ( $class, $dispatcher ) = @_;
1374
1375 if ($dispatcher) {
1376 $dispatcher = 'Catalyst::Dispatcher::' . $dispatcher;
1377 }
1378
1379 if ( $ENV{CATALYST_DISPATCHER} ) {
1380 $dispatcher = 'Catalyst::Dispatcher::' . $ENV{CATALYST_DISPATCHER};
1381 }
1382
1383 if ( $ENV{ uc($class) . '_DISPATCHER' } ) {
1384 $dispatcher =
1385 'Catalyst::Dispatcher::' . $ENV{ uc($class) . '_DISPATCHER' };
1386 }
1387
1388 unless ($dispatcher) {
1389 $dispatcher = 'Catalyst::Dispatcher';
1390 }
1391
1392 $dispatcher->require;
1393
1394 if ($@) {
1395 Catalyst::Exception->throw(
1396 message => qq/Couldn't load dispatcher "$dispatcher", "$@"/ );
1397 }
1398
1399 # dispatcher instance
1400 $class->dispatcher( $dispatcher->new );
1401}
1402
1403=item $c->setup_engine
1404
1405=cut
1406
1407sub setup_engine {
1408 my ( $class, $engine ) = @_;
1409
1410 if ($engine) {
1411 $engine = 'Catalyst::Engine::' . $engine;
1412 }
1413
1414 if ( $ENV{CATALYST_ENGINE} ) {
1415 $engine = 'Catalyst::Engine::' . $ENV{CATALYST_ENGINE};
1416 }
1417
1418 if ( $ENV{ uc($class) . '_ENGINE' } ) {
1419 $engine = 'Catalyst::Engine::' . $ENV{ uc($class) . '_ENGINE' };
1420 }
1421
1422 if ( !$engine && $ENV{MOD_PERL} ) {
1423
1424 # create the apache method
1425 {
1426 no strict 'refs';
1427 *{"$class\::apache"} = sub { shift->engine->apache };
1428 }
1429
1430 my ( $software, $version ) =
1431 $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
1432
1433 $version =~ s/_//g;
1434 $version =~ s/(\.[^.]+)\./$1/g;
1435
1436 if ( $software eq 'mod_perl' ) {
1437
1438 if ( $version >= 1.99922 ) {
1439 $engine = 'Catalyst::Engine::Apache2::MP20';
1440 }
1441
1442 elsif ( $version >= 1.9901 ) {
1443 $engine = 'Catalyst::Engine::Apache2::MP19';
1444 }
1445
1446 elsif ( $version >= 1.24 ) {
1447 $engine = 'Catalyst::Engine::Apache::MP13';
1448 }
1449
1450 else {
1451 Catalyst::Exception->throw( message =>
1452 qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
1453 }
1454
1455 # install the correct mod_perl handler
1456 if ( $version >= 1.9901 ) {
1457 *handler = sub : method {
1458 shift->handle_request(@_);
1459 };
1460 }
1461 else {
1462 *handler = sub ($$) { shift->handle_request(@_) };
1463 }
1464
1465 }
1466
1467 elsif ( $software eq 'Zeus-Perl' ) {
1468 $engine = 'Catalyst::Engine::Zeus';
1469 }
1470
1471 else {
1472 Catalyst::Exception->throw(
1473 message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
1474 }
1475 }
1476
1477 unless ($engine) {
1478 $engine = 'Catalyst::Engine::CGI';
1479 }
1480
1481 $engine->require;
1482
1483 if ($@) {
1484 Catalyst::Exception->throw( message =>
1485qq/Couldn't load engine "$engine" (maybe you forgot to install it?), "$@"/
1486 );
1487 }
0e7f5826 1488
d54484bf 1489 # check for old engines that are no longer compatible
1490 my $old_engine;
0e7f5826 1491 if ( $engine->isa('Catalyst::Engine::Apache')
1492 && !Catalyst::Engine::Apache->VERSION )
d54484bf 1493 {
1494 $old_engine = 1;
1495 }
0e7f5826 1496
d54484bf 1497 elsif ( $engine->isa('Catalyst::Engine::Server::Base')
0e7f5826 1498 && Catalyst::Engine::Server->VERSION le '0.02' )
d54484bf 1499 {
1500 $old_engine = 1;
1501 }
0e7f5826 1502
1503 elsif ($engine->isa('Catalyst::Engine::HTTP::POE')
1504 && $engine->VERSION eq '0.01' )
d54484bf 1505 {
1506 $old_engine = 1;
1507 }
0e7f5826 1508
1509 elsif ($engine->isa('Catalyst::Engine::Zeus')
1510 && $engine->VERSION eq '0.01' )
d54484bf 1511 {
1512 $old_engine = 1;
1513 }
fbcc39ad 1514
d54484bf 1515 if ($old_engine) {
1516 Catalyst::Exception->throw( message =>
0e7f5826 1517 qq/Engine "$engine" is not supported by this version of Catalyst/
d54484bf 1518 );
1519 }
0e7f5826 1520
fbcc39ad 1521 # engine instance
1522 $class->engine( $engine->new );
1523}
1524
1525=item $c->setup_home
1526
1527=cut
1528
1529sub setup_home {
1530 my ( $class, $home ) = @_;
1531
1532 if ( $ENV{CATALYST_HOME} ) {
1533 $home = $ENV{CATALYST_HOME};
1534 }
1535
1536 if ( $ENV{ uc($class) . '_HOME' } ) {
1537 $home = $ENV{ uc($class) . '_HOME' };
1538 }
1539
1540 unless ($home) {
1541 $home = Catalyst::Utils::home($class);
1542 }
1543
1544 if ($home) {
1545 $class->config->{home} ||= $home;
1546 $class->config->{root} ||= dir($home)->subdir('root');
1547 }
1548}
1549
1550=item $c->setup_log
1551
1552=cut
1553
1554sub setup_log {
1555 my ( $class, $debug ) = @_;
1556
1557 unless ( $class->log ) {
1558 $class->log( Catalyst::Log->new );
1559 }
1560
1561 if ( $ENV{CATALYST_DEBUG} || $ENV{ uc($class) . '_DEBUG' } || $debug ) {
1562 no strict 'refs';
1563 *{"$class\::debug"} = sub { 1 };
1564 $class->log->debug('Debug messages enabled');
1565 }
1566}
1567
1568=item $c->setup_plugins
1569
1570=cut
1571
1572sub setup_plugins {
1573 my ( $class, $plugins ) = @_;
1574
1575 $plugins ||= [];
1576 for my $plugin ( reverse @$plugins ) {
1577
1578 $plugin = "Catalyst::Plugin::$plugin";
1579
1580 $plugin->require;
1581
1582 if ($@) {
1583 Catalyst::Exception->throw(
1584 message => qq/Couldn't load plugin "$plugin", "$@"/ );
1585 }
1586
1587 {
1588 no strict 'refs';
1589 unshift @{"$class\::ISA"}, $plugin;
1590 }
1591 }
1592}
1593
1594=item $c->write( $data )
1595
1596Writes $data to the output stream. When using this method directly, you will
1597need to manually set the Content-Length header to the length of your output
1598data, if known.
1599
1600=cut
1601
4f5ebacd 1602sub write {
1603 my $c = shift;
1604
1605 # Finalize headers if someone manually writes output
1606 $c->finalize_headers;
1607
1608 return $c->engine->write( $c, @_ );
1609}
fbcc39ad 1610
bf88a181 1611=item version
1612
1613Returns the Catalyst version number. mostly useful for powered by messages
1614in template systems.
1615
1616=cut
1617
1618sub version { return $Catalyst::VERSION }
1619
23f9d934 1620=back
1621
b0bb11ec 1622=head1 INTERNAL ACTIONS
1623
1624Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>
1625C<_ACTION> and C<_END>, these are by default not shown in the private
1626action table.
1627
1628But you can deactivate this with a config parameter.
1629
1630 MyApp->config->{show_internal_actions} = 1;
1631
d2ee9760 1632=head1 CASE SENSITIVITY
1633
1634By default Catalyst is not case sensitive, so C<MyApp::C::FOO::Bar> becomes
1635C</foo/bar>.
1636
1637But you can activate case sensitivity with a config parameter.
1638
1639 MyApp->config->{case_sensitive} = 1;
1640
fbcc39ad 1641So C<MyApp::C::Foo::Bar> becomes C</Foo/Bar>.
1642
1643=head1 ON-DEMAND PARSER
1644
1645The request body is usually parsed at the beginning of a request,
1646but if you want to handle input yourself or speed things up a bit
1647you can enable on-demand parsing with a config parameter.
1648
1649 MyApp->config->{parse_on_demand} = 1;
1650
1651=head1 PROXY SUPPORT
1652
1653Many production servers operate using the common double-server approach, with
1654a lightweight frontend web server passing requests to a larger backend
1655server. An application running on the backend server must deal with two
1656problems: the remote user always appears to be '127.0.0.1' and the server's
1657hostname will appear to be 'localhost' regardless of the virtual host the
1658user connected through.
1659
1660Catalyst will automatically detect this situation when you are running both
1661the frontend and backend servers on the same machine. The following changes
1662are made to the request.
1663
1664 $c->req->address is set to the user's real IP address, as read from the
1665 HTTP_X_FORWARDED_FOR header.
1666
1667 The host value for $c->req->base and $c->req->uri is set to the real host,
1668 as read from the HTTP_X_FORWARDED_HOST header.
1669
1670Obviously, your web server must support these 2 headers for this to work.
1671
1672In a more complex server farm environment where you may have your frontend
1673proxy server(s) on different machines, you will need to set a configuration
1674option to tell Catalyst to read the proxied data from the headers.
1675
1676 MyApp->config->{using_frontend_proxy} = 1;
1677
1678If you do not wish to use the proxy support at all, you may set:
d1a31ac6 1679
fbcc39ad 1680 MyApp->config->{ignore_frontend_proxy} = 1;
1681
1682=head1 THREAD SAFETY
1683
1684Catalyst has been tested under Apache 2's threading mpm_worker, mpm_winnt,
1685and the standalone forking HTTP server on Windows. We believe the Catalyst
1686core to be thread-safe.
1687
1688If you plan to operate in a threaded environment, remember that all other
1689modules you are using must also be thread-safe. Some modules, most notably
1690DBD::SQLite, are not thread-safe.
d1a31ac6 1691
3cb1db8c 1692=head1 SUPPORT
1693
1694IRC:
1695
1696 Join #catalyst on irc.perl.org.
1697
1698Mailing-Lists:
1699
1700 http://lists.rawmode.org/mailman/listinfo/catalyst
1701 http://lists.rawmode.org/mailman/listinfo/catalyst-dev
1985c30b 1702
432d507d 1703Web:
1704
1705 http://catalyst.perl.org
1706
fc7ec1d9 1707=head1 SEE ALSO
1708
61b1e958 1709=over 4
1710
1711=item L<Catalyst::Manual> - The Catalyst Manual
1712
1713=item L<Catalyst::Engine> - Core Engine
1714
1715=item L<Catalyst::Log> - The Log Class.
1716
1717=item L<Catalyst::Request> - The Request Object
1718
1719=item L<Catalyst::Response> - The Response Object
1720
1721=item L<Catalyst::Test> - The test suite.
1722
1723=back
fc7ec1d9 1724
15f0b5b7 1725=head1 CREDITS
fc7ec1d9 1726
15f0b5b7 1727Andy Grundman
1728
fbcc39ad 1729Andy Wardley
1730
33108eaf 1731Andreas Marienborg
1732
f4a57de4 1733Andrew Bramble
1734
15f0b5b7 1735Andrew Ford
1736
1737Andrew Ruthven
1738
fbcc39ad 1739Arthur Bergman
1740
15f0b5b7 1741Autrijus Tang
1742
1743Christian Hansen
1744
1745Christopher Hicks
1746
1747Dan Sully
1748
1749Danijel Milicevic
1750
1751David Naughton
1752
1753Gary Ashton Jones
1754
1755Geoff Richards
1756
1757Jesse Sheidlower
1758
fbcc39ad 1759Jesse Vincent
1760
15f0b5b7 1761Jody Belka
1762
1763Johan Lindstrom
1764
1765Juan Camacho
1766
1767Leon Brocard
1768
1769Marcus Ramberg
1770
1771Matt S Trout
1772
71c3bcc3 1773Robert Sedlacek
1774
a727119f 1775Sam Vilain
1776
15f0b5b7 1777Tatsuhiko Miyagawa
fc7ec1d9 1778
51f0308d 1779Ulf Edvinsson
1780
bdcb95ef 1781Yuval Kogman
1782
51f0308d 1783=head1 AUTHOR
1784
1785Sebastian Riedel, C<sri@oook.de>
1786
fc7ec1d9 1787=head1 LICENSE
1788
9ce5ab63 1789This library is free software, you can redistribute it and/or modify it under
41ca9ba7 1790the same terms as Perl itself.
fc7ec1d9 1791
1792=cut
1793
17941;