use Catalyst::Controller;
use Data::OptList;
use Devel::InnerPackage ();
-use File::stat;
use Module::Pluggable::Object ();
use Text::SimpleTable ();
use Path::Class::Dir ();
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; }
# Remember to update this in Catalyst::Runtime as well!
-our $VERSION = '5.89001';
+our $VERSION = '5.89002';
sub import {
my ( $class, @arguments ) = @_;
# 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->_finalized_psgi_app, @_ ) }
+sub run {
+ my $c = shift;
+ $c->engine_loader->needs_psgi_engine_compat_hack ?
+ $c->_run_needs_psgi_engine_compat_hack(@_) :
+ $c->engine->run( $c, $c->_finalized_psgi_app, @_ );
+}
+
+sub _run_needs_psgi_engine_compat_hack {
+ my $c = shift;
+
+ ## We assume if they used the classic PSGI Engine, they must has CC:M
+ for my $metal (Catalyst::Controller::Metal->metals_for($c)) {
+ my $res = $metal->call(@_);
+ if (defined $res && !(ref $res eq 'ARRAY' && $res->[0] == 404)) {
+ return $res;
+ }
+ }
+
+ ## If we got this far, just do the psgi app
+ $c->_finalized_psgi_app->(@_)
+}
=head2 $c->set_action( $action, $code, $namespace, $attrs )
}
sub setup_engine {
- my ($class) = @_;
-
- $class->engine_loader(Catalyst::EngineLoader->new(application_name => $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);
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
}
- return $app->_wrapped_legacy_psgi_app;
+ return $app->_wrapped_legacy_psgi_app($app->psgi_app);
}
# Note - this is for back compatibility. Catalyst should not know or care about
# use the ReverseProxy middleware yourself if you want it in a .psgi
# file.
sub _wrapped_legacy_psgi_app {
- my ($app) = @_;
+ my ($app, $psgi_app) = @_;
- return Plack::Middleware::Conditional->wrap(
- $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->psgi_app
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