use Catalyst::Response;
use Catalyst::Utils;
use Catalyst::Controller;
+use Data::OptList;
use Devel::InnerPackage ();
use File::stat;
use Module::Pluggable::Object ();
use attributes;
use utf8;
use Carp qw/croak carp shortmess/;
+use Try::Tiny;
BEGIN { require 5.008004; }
__PACKAGE__->mk_classdata($_)
for qw/components arguments dispatcher engine log dispatcher_class
engine_class context_class request_class response_class stats_class
- setup_finished/;
+ setup_finished psgi_app/;
__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
-__PACKAGE__->engine_class('Catalyst::Engine::CGI');
+__PACKAGE__->engine_class('Catalyst::Engine');
__PACKAGE__->request_class('Catalyst::Request');
__PACKAGE__->response_class('Catalyst::Response');
__PACKAGE__->stats_class('Catalyst::Stats');
# Remember to update this in Catalyst::Runtime as well!
-our $VERSION = '5.80022';
+our $VERSION = '5.80024';
sub import {
my ( $class, @arguments ) = @_;
=head2 -Stats
-Enables statistics collection and reporting. You can also force this setting
-from the system environment with CATALYST_STATS or <MYAPP>_STATS. The
-environment settings override the application, with <MYAPP>_STATS having the
-highest priority.
+Enables statistics collection and reporting.
-e.g.
+ use Catalyst qw/-Stats=1/;
- use Catalyst qw/-Stats=1/
+You can also force this setting from the system environment with CATALYST_STATS
+or <MYAPP>_STATS. The environment settings override the application, with
+<MYAPP>_STATS having the highest priority.
+
+Stats are also enabled if L<< debugging |/"-Debug" >> is enabled.
=head1 METHODS
carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
foreach my $arg (@args) {
utf8::encode($arg) if utf8::is_utf8($arg);
- }
- s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args;
- if (blessed $path) { # Action object only.
- s|/|%2F|g for @args;
+ $arg =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
}
if ( blessed($path) ) { # action object
+ s|/|%2F|g for @args;
my $captures = [ map { s|/|%2F|g; $_; }
( scalar @args && ref $args[0] eq 'ARRAY'
? @{ shift(@args) }
$path = '/' if $path eq '';
}
- undef($path) if (defined $path && $path eq '');
-
unshift(@args, $path);
unless (defined $path && $path =~ s!^/!!) { # in-place strip
# join args with '/', or a blank string
my $args = join('/', grep { defined($_) } @args);
$args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
-# $args =~ s!^/+!!;
+ $args =~ s!^/+!!;
my $base = $c->req->base;
my $class = ref($base);
$base =~ s{(?<!/)$}{/};
sub get_actions { my $c = shift; $c->dispatcher->get_actions( $c, @_ ) }
-=head2 $c->handle_request( $class, @arguments )
+=head2 $app->handle_request( @arguments )
Called to handle each HTTP request.
# Always expect worst case!
my $status = -1;
- eval {
+ try {
if ($class->debug) {
my $secs = time - $START || 1;
my $av = sprintf '%.3f', $COUNT / $secs;
my $c = $class->prepare(@arguments);
$c->dispatch;
$status = $c->finalize;
- };
-
- if ( my $error = $@ ) {
- chomp $error;
- $class->log->error(qq/Caught exception in engine "$error"/);
}
+ catch {
+ chomp(my $error = $_);
+ $class->log->error(qq/Caught exception in engine "$error"/);
+ };
$COUNT++;
$c->res->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
}
- #XXX reuse coderef from can
- # Allow engine to direct the prepare flow (for POE)
- if ( $c->engine->can('prepare') ) {
- $c->engine->prepare( $c, @arguments );
- }
- else {
- $c->prepare_request(@arguments);
- $c->prepare_connection;
- $c->prepare_query_parameters;
- $c->prepare_headers;
- $c->prepare_cookies;
- $c->prepare_path;
-
- # Prepare the body for reading, either by prepare_body
- # or the user, if they are using $c->read
- $c->prepare_read;
-
- # Parse the body unless the user wants it on-demand
- unless ( ref($c)->config->{parse_on_demand} ) {
- $c->prepare_body;
+ try {
+ # Allow engine to direct the prepare flow (for POE)
+ if ( my $prepare = $c->engine->can('prepare') ) {
+ $c->engine->$prepare( $c, @arguments );
+ }
+ else {
+ $c->prepare_request(@arguments);
+ $c->prepare_connection;
+ $c->prepare_query_parameters;
+ $c->prepare_headers;
+ $c->prepare_cookies;
+ $c->prepare_path;
+
+ # Prepare the body for reading, either by prepare_body
+ # or the user, if they are using $c->read
+ $c->prepare_read;
+
+ # Parse the body unless the user wants it on-demand
+ unless ( ref($c)->config->{parse_on_demand} ) {
+ $c->prepare_body;
+ }
}
}
+ # VERY ugly and probably shouldn't rely on ->finalize actually working
+ catch {
+ # failed prepare is always due to an invalid request, right?
+ $c->response->status(400);
+ $c->response->content_type('text/plain');
+ $c->response->body('Bad Request');
+ $c->finalize;
+ die $_;
+ };
my $method = $c->req->method || '';
my $path = $c->req->path;
# we know M::P::O found a file on disk so this is safe
Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
-
- # Needs to be done as soon as the component is loaded, as loading a sub-component
- # (next time round the loop) can cause us to get the wrong metaclass..
- $class->_controller_init_base_classes($component);
}
for my $component (@comps) {
: $class->expand_component_module( $component, $config );
for my $component (@expanded_components) {
next if $comps{$component};
- $class->_controller_init_base_classes($component); # Also cover inner packages
$class->components->{ $component } = $class->setup_component($component);
}
}
=cut
-# FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes
-# nearest to Catalyst::Controller first, no matter what order stuff happens
-# to be loaded. There are TODO tests in Moose for this, see
-# f2391d17574eff81d911b97be15ea51080500003
-sub _controller_init_base_classes {
- my ($app_class, $component) = @_;
- return unless $component->isa('Catalyst::Controller');
- foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) {
- Moose::Meta::Class->initialize( $class )
- unless find_meta($class);
- }
-}
-
sub setup_component {
my( $class, $component ) = @_;
=cut
sub setup_engine {
- my ( $class, $engine ) = @_;
-
- if ($engine) {
- $engine = 'Catalyst::Engine::' . $engine;
- }
-
- if ( my $env = Catalyst::Utils::env_value( $class, 'ENGINE' ) ) {
- $engine = 'Catalyst::Engine::' . $env;
- }
-
- if ( $ENV{MOD_PERL} ) {
- my $meta = Class::MOP::get_metaclass_by_name($class);
-
- # create the apache method
- $meta->add_method('apache' => sub { shift->engine->apache });
-
- my ( $software, $version ) =
- $ENV{MOD_PERL} =~ /^(\S+)\/(\d+(?:[\.\_]\d+)+)/;
-
- $version =~ s/_//g;
- $version =~ s/(\.[^.]+)\./$1/g;
-
- if ( $software eq 'mod_perl' ) {
-
- if ( !$engine ) {
-
- if ( $version >= 1.99922 ) {
- $engine = 'Catalyst::Engine::Apache2::MP20';
- }
-
- elsif ( $version >= 1.9901 ) {
- $engine = 'Catalyst::Engine::Apache2::MP19';
- }
-
- elsif ( $version >= 1.24 ) {
- $engine = 'Catalyst::Engine::Apache::MP13';
- }
-
- else {
- Catalyst::Exception->throw( message =>
- qq/Unsupported mod_perl version: $ENV{MOD_PERL}/ );
- }
-
- }
-
- # install the correct mod_perl handler
- if ( $version >= 1.9901 ) {
- *handler = sub : method {
- shift->handle_request(@_);
- };
- }
- else {
- *handler = sub ($$) { shift->handle_request(@_) };
- }
-
- }
-
- elsif ( $software eq 'Zeus-Perl' ) {
- $engine = 'Catalyst::Engine::Zeus';
- }
-
- else {
- Catalyst::Exception->throw(
- message => qq/Unsupported mod_perl: $ENV{MOD_PERL}/ );
- }
- }
+ my ($class, $engine) = @_;
unless ($engine) {
$engine = $class->engine_class;
}
+ $engine = 'Catalyst::Engine::' . $engine
+ unless $engine =~ /^Catalyst::Engine/;
+
+ $engine = 'Catalyst::Engine' if $engine eq 'Catalyst::Engine::HTTP';
Class::MOP::load_class($engine);
);
}
- # engine instance
$class->engine( $engine->new );
+ $class->psgi_app( $class->engine->build_psgi_app($class) );
}
=head2 $c->setup_home
my ( $class, $plugins ) = @_;
$class->_plugins( {} ) unless $class->_plugins;
- $plugins ||= [];
+ $plugins = Data::OptList::mkopt($plugins || []);
- my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
+ my @plugins = map {
+ [ Catalyst::Utils::resolve_namespace(
+ $class . '::Plugin',
+ 'Catalyst::Plugin', $_->[0]
+ ),
+ $_->[1],
+ ]
+ } @{ $plugins };
for my $plugin ( reverse @plugins ) {
- Class::MOP::load_class($plugin);
- my $meta = find_meta($plugin);
+ Class::MOP::load_class($plugin->[0], $plugin->[1]);
+ my $meta = find_meta($plugin->[0]);
next if $meta && $meta->isa('Moose::Meta::Role');
- $class->_register_plugin($plugin);
+ $class->_register_plugin($plugin->[0]);
}
my @roles =
- map { $_->name }
- grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
- map { find_meta($_) }
+ map { $_->[0]->name, $_->[1] }
+ grep { blessed($_->[0]) && $_->[0]->isa('Moose::Meta::Role') }
+ map { [find_meta($_->[0]), $_->[1]] }
@plugins;
Moose::Util::apply_all_roles(
Returns an arrayref of the internal execution stack (actions that are
currently executing).
+=head2 $c->stats
+
+Returns the current timing statistics object. By default Catalyst uses
+L<Catalyst::Stats|Catalyst::Stats>, but can be set otherwise with
+L<< stats_class|/"$c->stats_class" >>.
+
+Even if L<< -Stats|/"-Stats" >> is not enabled, the stats object is still
+available. By enabling it with C< $c->stats->enabled(1) >, it can be used to
+profile explicitly, although MyApp.pm still won't profile nor output anything
+by itself.
+
=head2 $c->stats_class
-Returns or sets the stats (timing statistics) class.
+Returns or sets the stats (timing statistics) class. L<Catalyst::Stats|Catalyst::Stats> is used by default.
=head2 $c->use_stats
-Returns 1 when stats collection is enabled. Stats collection is enabled
-when the -Stats options is set, debug is on or when the <MYAPP>_STATS
-environment variable is set.
+Returns 1 when L<< stats collection|/"-Stats" >> is enabled.
Note that this is a static method, not an accessor and should be overridden
by declaring C<sub use_stats { 1 }> in your MyApp.pm, not by calling C<< $c->use_stats(1) >>.
=item *
+C<use_request_uri_for_path> - Controlls if the C<REQUEST_URI> or C<PATH_INFO> environment
+variable should be used for determining the request path. See L<Catalyst::Engine::CGI/PATH DECODING>
+for more information.
+
+=item *
+
C<using_frontend_proxy> - See L</PROXY SUPPORT>.
=back
Robert Sedlacek C<< <rs@474.at> >>
+SpiceMan: Marcel Montes
+
sky: Arthur Bergman
szbalint: Balint Szilakszi <szbalint@cpan.org>
willert: Sebastian Willert <willert@cpan.org>
+wreis: Wallace Reis <wallace@reis.org.br>
+
Yuval Kogman, C<nothingmuch@woobling.org>
=head1 LICENSE