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