Make legacy IIS env fixing work again
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index 173483a..39962a6 100644 (file)
@@ -30,9 +30,12 @@ use Class::C3::Adopt::NEXT;
 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; }
 
@@ -70,18 +73,17 @@ our $GO        = Catalyst::Exception::Go->new;
 #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.80029';
+our $VERSION = '5.89002';
 
 sub import {
     my ( $class, @arguments ) = @_;
@@ -1665,7 +1667,9 @@ sub execute {
     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;
 
@@ -1862,7 +1866,7 @@ sub finalize_headers {
     }
 
     # Content-Length
-    if ( $response->body && !$response->content_length ) {
+    if ( defined $response->body && length $response->body && !$response->content_length ) {
 
         # get the length from a filehandle
         if ( blessed( $response->body ) && $response->body->can('read') || ref( $response->body ) eq 'GLOB' )
@@ -2376,11 +2380,11 @@ sub prepare_write { my $c = shift; $c->engine->prepare_write( $c, @_ ) }
 
 =head2 $c->request_class
 
-Returns or sets the request class.
+Returns or sets the request class. Defaults to L<Catalyst::Request>.
 
 =head2 $c->response_class
 
-Returns or sets the response class.
+Returns or sets the response class. Defaults to L<Catalyst::Response>.
 
 =head2 $c->read( [$maxlength] )
 
@@ -2405,7 +2409,7 @@ Starts the engine.
 
 =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 )
 
@@ -2589,20 +2593,26 @@ Sets up engine.
 
 =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);
         });
     }
 
@@ -2611,44 +2621,18 @@ sub setup_engine {
     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})) {
@@ -2660,8 +2644,18 @@ sub setup_psgi_app {
             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) = @_;
@@ -2670,18 +2664,79 @@ sub setup_psgi_app {
                 || $app->config->{using_frontend_proxy};
         },
     );
+
+    # 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,
+        builder => sub {
+            my ($to_wrap) = @_;
+            return sub {
+                my ($env) = @_;
+                $env->{PATH_INFO} ||= delete $env->{SCRIPT_NAME};
+                return $to_wrap->($env);
+            };
+        },
+        condition => sub {
+            my ($env) = @_;
+            my $server = $env->{SERVER_SOFTWARE};
+            return unless $server;
+            return $server =~ /lighttpd/ ? 1 : 0;
+        },
+    );
+
+    $psgi_app = Plack::Middleware::Conditional->wrap(
+        $psgi_app,
+        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);
+            };
+        },
+        condition => sub {
+            my ($env) = @_;
+            my $server = $env->{SERVER_SOFTWARE};
+            return unless $server;
+            return $server =~ /IIS\/[6-9]\.[0-9]/ ? 1 : 0;
+        },
+    );
+
+    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);
 }
@@ -3225,6 +3280,8 @@ Yuval Kogman, C<nothingmuch@woobling.org>
 
 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