use Catalyst::Controller;
use Data::OptList;
use Devel::InnerPackage ();
-use File::stat;
use Module::Pluggable::Object ();
use Text::SimpleTable ();
use Path::Class::Dir ();
use List::MoreUtils qw/uniq/;
use attributes;
use String::RewritePrefix;
+use Catalyst::EngineLoader;
use utf8;
use Carp qw/croak carp shortmess/;
use Try::Tiny;
+use Plack::Middleware::Conditional;
+use Plack::Middleware::ReverseProxy;
+use Plack::Middleware::IIS6ScriptNameFix;
+use Plack::Middleware::LighttpdScriptNameFix;
BEGIN { require 5.008004; }
#maybe we should just make them attributes with a default?
__PACKAGE__->mk_classdata($_)
for qw/components arguments dispatcher engine log dispatcher_class
- engine_class context_class request_class response_class stats_class
+ engine_loader context_class request_class response_class stats_class
setup_finished _psgi_app/;
__PACKAGE__->dispatcher_class('Catalyst::Dispatcher');
-__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.89000';
+our $VERSION = '5.89002';
sub import {
my ( $class, @arguments ) = @_;
return $c->_filter_component( $comp, @args ) if $comp;
}
+ return
+ if $c->config->{disable_component_resolution_regex_fallback};
+
# This is here so $c->comp( '::M::' ) works
my $query = ref $name ? $name : qr{$name}i;
A hook to attach modifiers to. This method does not do anything except set the
C<setup_finished> accessor.
-Applying method modifiers to the C<setup> method doesn't work, because of quirky thingsdone for plugin setup.
+Applying method modifiers to the C<setup> method doesn't work, because of quirky things done for plugin setup.
Example:
push( @{ $c->stack }, $code );
no warnings 'recursion';
- eval { $c->state( $code->execute( $class, $c, @{ $c->req->args } ) || 0 ) };
+ # N.B. This used to be combined, but I have seen $c get clobbered if so, and
+ # I have no idea how, ergo $ret (which appears to fix the issue)
+ eval { my $ret = $code->execute( $class, $c, @{ $c->req->args } ) || 0; $c->state( $ret ) };
$c->_stats_finish_execute( $stats_info ) if $c->use_stats and $stats_info;
$error = qq/Caught exception in $class->$name "$error"/;
}
$c->error($error);
- $c->state(0);
}
+ $c->state(0);
}
return $c->state;
}
# get the length from a filehandle
if ( blessed( $response->body ) && $response->body->can('read') || ref( $response->body ) eq 'GLOB' )
{
- my $stat = stat $response->body;
- if ( $stat && $stat->size > 0 ) {
- $response->content_length( $stat->size );
+ my $size = -s $response->body;
+ if ( $size ) {
+ $response->content_length( $size );
}
else {
$c->log->warn('Serving filehandle without a content-length');
=cut
-sub run { my $c = shift; return $c->engine->run( $c, $c->psgi_app, @_ ) }
+sub run { my $c = shift; return $c->engine->run( $c, $c->_finalized_psgi_app, @_ ) }
=head2 $c->set_action( $action, $code, $namespace, $attrs )
=cut
+sub engine_class {
+ my $class = shift;
+ $class->engine_loader->catalyst_engine_class(@_);
+}
+
sub setup_engine {
- my ($class) = @_;
+ my ($class, $requested_engine) = @_;
+
+ $class->engine_loader(
+ Catalyst::EngineLoader->new({
+ application_name => $class,
+ (defined $requested_engine
+ ? (requested_engine => $requested_engine) : ()),
+ }),
+ );
my $engine = $class->engine_class;
Class::MOP::load_class($engine);
if ($ENV{MOD_PERL}) {
- require 'Catalyst/Engine/Loader.pm';
- my $apache = Catalyst::Engine::Loader->auto;
+ my $apache = $class->engine_loader->auto;
# FIXME - Immutable
$class->meta->add_method(handler => sub {
my $r = shift;
- my $app = $class->psgi_app;
- $apache->call_app($r, $app);
+ my $psgi_app = $class->psgi_app;
+ $apache->call_app($r, $psgi_app);
});
}
return;
}
-=head2 $c->psgi_app
-
-Builds a PSGI application coderef for the catalyst application C<$c> using
-L</"$c->setup_psgi_app">, stores it internally, and returns it. On the next call
-to this method, C<setup_psgi_app> won't be invoked again, but its persisted
-return value of it will be returned.
-
-This is the top-level entrypoint for things that need a full blown Catalyst PSGI
-app. If you only need the raw PSGI application, without any middlewares, use
-L</"$c->raw_psgi_app"> instead.
-
-=cut
-
-sub psgi_app {
+sub _finalized_psgi_app {
my ($app) = @_;
unless ($app->_psgi_app) {
- my $psgi_app = $app->setup_psgi_app;
+ my $psgi_app = $app->_setup_psgi_app;
$app->_psgi_app($psgi_app);
}
return $app->_psgi_app;
}
-=head2 $c->setup_psgi_app
-
-Builds a PSGI application coderef for the catalyst application C<$c>.
-
-If we're able to locate a C<${myapp}.psgi> file in the applications home
-directory, we'll use that to obtain our code reference.
-
-Otherwise the raw psgi app, without any middlewares is created using
-C<raw_psgi_app> and wrapped into L<Plack::Middleware::ReverseProxy>
-conditionally. See L</"PROXY SUPPORT">.
-
-=cut
-
-sub setup_psgi_app {
+sub _setup_psgi_app {
my ($app) = @_;
- if (my $home = Path::Class::Dir->new($app->config->{home})) {
+ for my $home (Path::Class::Dir->new($app->config->{home})) {
my $psgi_file = $home->file(
Catalyst::Utils::appprefix($app) . '.psgi',
);
- return Plack::Util::load_psgi($psgi_file)
- if -e $psgi_file;
+ next unless -e $psgi_file;
+ my $psgi_app = Plack::Util::load_psgi($psgi_file);
+
+ return $psgi_app
+ unless $app->engine_loader->needs_psgi_engine_compat_hack;
+
+ # load_psgi ran a .psgi file doing ->setup_engine('PSGI'). That's what
+ # .psgi files generated by the old Engine::PSGI do. Those return an app
+ # coderef calling into MyApp->run, which doesn't work anymore, so we're
+ # just ignoring it and use the wrapped legacy psgi app
+ warn <<"EOW";
+Found a legacy Catalyst::Engine::PSGI .psgi file at ${psgi_file}.
+
+Its content has been ignored. Please consult the Catalyst::Upgrading
+documentation on how to upgrade from Catalyst::Engine::PSGI.
+EOW
}
- # Note - this is for back compatibility. Catalyst should not know
- # or care about how it's deployed. The recommended way of
- # configuring this is now to use the ReverseProxy middleware
- # yourself if you want it in a .psgi file.
- return Plack::Middleware::Conditional->wrap(
- $app->raw_psgi_app,
+ return $app->apply_default_middlewares($app->psgi_app);
+}
+
+=head2 $c->apply_default_middlewares
+
+Adds the following L<Plack> middlewares to your application, since they are
+useful and commonly needed:
+
+L<Plack::Middleware::ReverseProxy>, (conditionally added based on the status
+of your $ENV{REMOTE_ADDR}, and can be forced on with C<using_frontend_proxy>
+or forced off with C<ignore_frontend_proxy>), L<Plack::Middleware::LighttpdScriptNameFix>
+(if you are using Lighttpd), L<Plack::Middleware::IIS6ScriptNameFix> (always
+applied since this middleware is smart enough to conditionally apply itself).
+
+Additionally if we detect we are using Nginx, we add a bit of custom middleware
+to solve some problems with the way that server handles $ENV{PATH_INFO} and
+$ENV{SCRIPT_NAME}
+
+=cut
+
+
+sub apply_default_middlewares {
+ my ($app, $psgi_app) = @_;
+
+ $psgi_app = Plack::Middleware::Conditional->wrap(
+ $psgi_app,
builder => sub { Plack::Middleware::ReverseProxy->wrap($_[0]) },
condition => sub {
my ($env) = @_;
|| $app->config->{using_frontend_proxy};
},
);
+
+ my $server_matches = sub {
+ my ($re) = @_;
+ return sub {
+ my ($env) = @_;
+ my $server = $env->{SERVER_SOFTWARE};
+ return unless $server;
+ return $server =~ $re ? 1 : 0;
+ };
+ };
+
+ # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME
+ # http://lists.scsys.co.uk/pipermail/catalyst/2006-June/008361.html
+ $psgi_app = Plack::Middleware::LighttpdScriptNameFix->wrap($psgi_app);
+
+ $psgi_app = Plack::Middleware::Conditional->wrap(
+ $psgi_app,
+ condition => $server_matches->(qr/^nginx/),
+ builder => sub {
+ my ($to_wrap) = @_;
+ return sub {
+ my ($env) = @_;
+ my $script_name = $env->{SCRIPT_NAME};
+ $env->{PATH_INFO} =~ s/^$script_name//g;
+ return $to_wrap->($env);
+ };
+ },
+ );
+
+ # we're applying this unconditionally as the middleware itself already makes
+ # sure it doesn't fuck things up if it's not running under one of the right
+ # IIS versions
+ $psgi_app = Plack::Middleware::IIS6ScriptNameFix->wrap($psgi_app);
+
+ return $psgi_app;
}
-=head2 $c->raw_psgi_app
+=head2 $c->psgi_app
Returns a PSGI application code reference for the catalyst application
C<$c>. This is the bare application without any middlewares
-applied. C<${myapp}.psgi> is not taken into account. See
-L</"$c->setup_psgi_app">.
+applied. C<${myapp}.psgi> is not taken into account.
+
+This is what you want to be using to retrieve the PSGI application code
+reference of your Catalyst application for use in F<.psgi> files.
=cut
-sub raw_psgi_app {
+sub psgi_app {
my ($app) = @_;
return $app->engine->build_psgi_app($app);
}
my $class = ref $proto || $proto;
Class::MOP::load_class( $plugin );
- $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is decated and will not work in 5.81" )
+ $class->log->warn( "$plugin inherits from 'Catalyst::Component' - this is deprecated and will not work in 5.81" )
if $plugin->isa( 'Catalyst::Component' );
$proto->_plugins->{$plugin} = 1;
unless ($instant) {
rainboxx: Matthias Dietrich, C<perl@rainboxx.de>
+dd070: Dhaval Dhanani <dhaval070@gmail.com>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2005, the above named PROJECT FOUNDER and CONTRIBUTORS.
+
=head1 LICENSE
This library is free software. You can redistribute it and/or modify it under