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;
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 ) = @_;
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;
=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) = @_;
+ $class->engine_loader(Catalyst::EngineLoader->new(application_name => $class));
+
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})) {
if -e $psgi_file;
}
- return Plack::Middleware::Conditional->wrap(
- $app->raw_psgi_app,
+ return $app->_wrapped_legacy_psgi_app($app->psgi_app);
+}
+
+# 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.
+sub _wrapped_legacy_psgi_app {
+ 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
+ # Thanks to Mark Blythe for this fix
+ #
+ # Note that this has probably the same effect as
+ # Plack::Middleware::LighttpdScriptNameFix and we should switch to that if
+ # we can.
+ $psgi_app = Plack::Middleware::Conditional->wrap(
+ $psgi_app,
+ condition => $server_matches->(qr/lighttpd/),
+ builder => sub {
+ my ($to_wrap) = @_;
+ return sub {
+ my ($env) = @_;
+ $env->{PATH_INFO} ||= delete $env->{SCRIPT_NAME};
+ return $to_wrap->($env);
+ };
+ },
+ );
+
+ $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);
+ };
+ },
+ );
+
+ $psgi_app = Plack::Middleware::Conditional->wrap(
+ $psgi_app,
+ condition => $server_matches->(qr/IIS\/[6-9]\.[0-9]/),
+ builder => sub {
+ my ($to_wrap) = @_;
+ return sub {
+ my ($env) = @_;
+
+ my @script_name = split(m!/!, $env->{PATH_INFO});
+ my @path_translated = split(m!/|\\\\?!, $env->{PATH_TRANSLATED});
+ my @path_info;
+
+ while ($script_name[$#script_name] eq $path_translated[$#path_translated]) {
+ pop(@path_translated);
+ unshift(@path_info, pop(@script_name));
+ }
+
+ unshift(@path_info, '', '');
+
+ $env->{PATH_INFO} = join('/', @path_info);
+ $env->{SCRIPT_NAME} = join('/', @script_name);
+
+ return $to_wrap->($env);
+ };
+ },
+ );
+
+ 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);
}
rainboxx: Matthias Dietrich, C<perl@rainboxx.de>
+dd070: Dhaval Dhanani <dhaval070@gmail.com>
+
=head1 LICENSE
This library is free software. You can redistribute it and/or modify it under