X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst.pm;h=03ce6ab1f5adbe25916dc7ae0ba5e2c18de8d598;hb=ccfec942b305481ff0c471d353e2663b1f768bf9;hp=02110edae7857254bf3d733b0bae4f7f980b0222;hpb=b1ededd4680eff1d4ddb42ed860884e361804fe1;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 02110ed..03ce6ab 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -16,7 +16,6 @@ use Catalyst::Utils; use Catalyst::Controller; use Data::OptList; use Devel::InnerPackage (); -use File::stat; use Module::Pluggable::Object (); use Text::SimpleTable (); use Path::Class::Dir (); @@ -34,6 +33,10 @@ 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; } @@ -81,7 +84,7 @@ __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 ) = @_; @@ -1869,9 +1872,9 @@ sub finalize_headers { # 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'); @@ -2407,7 +2410,27 @@ Starts the engine. =cut -sub run { my $c = shift; return $c->engine->run( $c, $c->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 ) @@ -2597,9 +2620,15 @@ sub engine_class { } 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); @@ -2619,61 +2648,53 @@ sub setup_engine { return; } -=head2 $c->psgi_app - -Builds a PSGI application coderef for the catalyst application C<$c> using -Lsetup_psgi_app">, stores it internally, and returns it. On the next call -to this method, C 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 -Lraw_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 and wrapped into L -conditionally. See L. - -=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); +} + +# FIXME - document me + +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) = @_; @@ -2682,18 +2703,55 @@ sub setup_psgi_app { || $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 -Lsetup_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); } @@ -3239,6 +3297,10 @@ rainboxx: Matthias Dietrich, C dd070: Dhaval Dhanani +=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