May be the last setup method
[catagits/Catalyst-Plugin-Static-Simple.git] / lib / Catalyst / Plugin / Static / Simple.pm
index a36ecb8..03aecd0 100644 (file)
@@ -7,8 +7,9 @@ use File::stat;
 use File::Spec ();
 use IO::File ();
 use MIME::Types ();
+use MRO::Compat;
 
-our $VERSION = '0.15';
+our $VERSION = '0.21';
 
 __PACKAGE__->mk_accessors( qw/_static_file _static_debug_message/ );
 
@@ -22,18 +23,23 @@ sub prepare_action {
     # is the URI in a static-defined path?
     foreach my $dir ( @{ $config->{dirs} } ) {
         my $dir_re = quotemeta $dir;
-        my $re = ( $dir =~ m{^qr/}xms ) ? eval $dir : qr/^${dir_re}/;
+        
+        # strip trailing slashes, they'll be added in our regex
+        $dir_re =~ s{/$}{};
+        
+        my $re = ( $dir =~ m{^qr/}xms ) ? eval $dir : qr{^${dir_re}/};
         if ($@) {
             $c->error( "Error compiling static dir regex '$dir': $@" );
         }
         if ( $path =~ $re ) {
-            if ( $c->_locate_static_file( $path ) ) {
+            if ( $c->_locate_static_file( $path, 1 ) ) {
                 $c->_debug_msg( 'from static directory' )
                     if $config->{debug};
             } else {
                 $c->_debug_msg( "404: file not found: $path" )
                     if $config->{debug};
                 $c->res->status( 404 );
+                $c->res->content_type( 'text/html' );
             }
         }
     }
@@ -44,7 +50,7 @@ sub prepare_action {
         $c->_locate_static_file( $path );
     }
     
-    return $c->NEXT::ACTUAL::prepare_action(@_);
+    return $c->next::method(@_);
 }
 
 sub dispatch {
@@ -59,7 +65,7 @@ sub dispatch {
         return $c->_serve_static;
     }
     else {
-        return $c->NEXT::ACTUAL::dispatch(@_);
+        return $c->next::method(@_);
     }
 }
 
@@ -71,18 +77,13 @@ sub finalize {
         $c->log->debug( 'Static::Simple: ' . join q{ }, @{$c->_debug_msg} );
     }
     
-    if ( $c->res->status =~ /^(1\d\d|[23]04)$/xms ) {
-        $c->res->headers->remove_content_headers;
-        return $c->finalize_headers;
-    }
-    
-    return $c->NEXT::ACTUAL::finalize(@_);
+    return $c->next::method(@_);
 }
 
 sub setup {
     my $c = shift;
     
-    $c->NEXT::setup(@_);
+    $c->maybe::next::method(@_);
     
     if ( Catalyst->VERSION le '5.33' ) {
         require File::Slurp;
@@ -97,6 +98,7 @@ sub setup {
     $config->{ignore_dirs} ||= [];
     $config->{debug} ||= $c->debug;
     $config->{no_logs} = 1 unless defined $config->{no_logs};
+    $config->{no_logs} = 0 if $config->{logging};
     
     # load up a MIME::Types object, only loading types with
     # at least 1 file extension
@@ -109,7 +111,7 @@ sub setup {
 # Search through all included directories for the static file
 # Based on Template Toolkit INCLUDE_PATH code
 sub _locate_static_file {
-    my ( $c, $path ) = @_;
+    my ( $c, $path, $in_static_dir ) = @_;
     
     $path = File::Spec->catdir(
         File::Spec->no_upwards( File::Spec->splitdir( $path ) ) 
@@ -136,22 +138,25 @@ sub _locate_static_file {
             $dir =~ s/(\/|\\)$//xms;
             if ( -d $dir && -f $dir . '/' . $path ) {
                 
-                # do we need to ignore the file?
-                for my $ignore ( @{ $config->{ignore_dirs} } ) {
-                    $ignore =~ s{(/|\\)$}{};
-                    if ( $path =~ /^$ignore(\/|\\)/ ) {
-                        $c->_debug_msg( "Ignoring directory `$ignore`" )
-                            if $config->{debug};
-                        next DIR_CHECK;
+                # Don't ignore any files in static dirs defined with 'dirs'
+                unless ( $in_static_dir ) {
+                    # do we need to ignore the file?
+                    for my $ignore ( @{ $config->{ignore_dirs} } ) {
+                        $ignore =~ s{(/|\\)$}{};
+                        if ( $path =~ /^$ignore(\/|\\)/ ) {
+                            $c->_debug_msg( "Ignoring directory `$ignore`" )
+                                if $config->{debug};
+                            next DIR_CHECK;
+                        }
                     }
-                }
                 
-                # do we need to ignore based on extension?
-                for my $ignore_ext ( @{ $config->{ignore_extensions} } ) {
-                    if ( $path =~ /.*\.${ignore_ext}$/ixms ) {
-                        $c->_debug_msg( "Ignoring extension `$ignore_ext`" )
-                            if $config->{debug};
-                        next DIR_CHECK;
+                    # do we need to ignore based on extension?
+                    for my $ignore_ext ( @{ $config->{ignore_extensions} } ) {
+                        if ( $path =~ /.*\.${ignore_ext}$/ixms ) {
+                            $c->_debug_msg( "Ignoring extension `$ignore_ext`" )
+                                if $config->{debug};
+                            next DIR_CHECK;
+                        }
                     }
                 }
                 
@@ -168,7 +173,7 @@ sub _locate_static_file {
 sub _serve_static {
     my $c = shift;
            
-    my $full_path = $c->_static_file;
+    my $full_path = shift || $c->_static_file;
     my $type      = $c->_ext_to_type( $full_path );
     my $stat      = stat $full_path;
 
@@ -197,6 +202,26 @@ sub _serve_static {
     return 1;
 }
 
+sub serve_static_file {
+    my ( $c, $full_path ) = @_;
+
+    my $config = $c->config->{static} ||= {};
+    
+    if ( -e $full_path ) {
+        $c->_debug_msg( "Serving static file: $full_path" )
+            if $config->{debug};
+    }
+    else {
+        $c->_debug_msg( "404: file not found: $full_path" )
+            if $config->{debug};
+        $c->res->status( 404 );
+        $c->res->content_type( 'text/html' );
+        return;
+    }
+
+    $c->_serve_static( $full_path );
+}
+
 # looks up the correct MIME type for the current file extension
 sub _ext_to_type {
     my ( $c, $full_path ) = @_;
@@ -249,9 +274,12 @@ Catalyst::Plugin::Static::Simple - Make serving static pages painless.
 
     use Catalyst;
     MyApp->setup( qw/Static::Simple/ );
-    # that's it; static content is automatically served by
-    # Catalyst, though you can configure things or bypass
-    # Catalyst entirely in a production environment
+    # that's it; static content is automatically served by Catalyst
+    # from the application's root directory, though you can configure
+    # things or bypass Catalyst entirely in a production environment
+    #
+    # one caveat: the files must be served from an absolute path
+    # (i.e. /images/foo.png)
 
 =head1 DESCRIPTION
 
@@ -305,7 +333,7 @@ Since Catalyst 5.50, logging of static requests is turned off by
 default; static requests tend to clutter the log output and rarely
 reveal anything useful. However, if you want to enable logging of static
 requests, you can do so by setting
-C<MyApp-E<gt>config-E<gt>{static}-E<gt>{no_logs}> to 0.
+C<MyApp-E<gt>config-E<gt>{static}-E<gt>{logging}> to 1.
 
 =head2 Forcing directories into static mode
 
@@ -413,13 +441,14 @@ is automatically enabled when running Catalyst in -Debug mode.
     
 =head1 USING WITH APACHE
 
-While Static::Simple will work just fine serving files through Catalyst in
-mod_perl, for increased performance, you may wish to have Apache handle the
-serving of your static files.  To do this, simply use a dedicated directory
-for your static files and configure an Apache Location block for that
-directory.  This approach is recommended for production installations.
+While Static::Simple will work just fine serving files through Catalyst
+in mod_perl, for increased performance you may wish to have Apache
+handle the serving of your static files directly. To do this, simply use
+a dedicated directory for your static files and configure an Apache
+Location block for that directory  This approach is recommended for
+production installations.
 
-    <Location /static>
+    <Location /myapp/static>
         SetHandler default-handler
     </Location>
 
@@ -428,6 +457,44 @@ through Catalyst. You can leave Static::Simple as part of your
 application, and it will continue to function on a development server,
 or using Catalyst's built-in server.
 
+In practice, your Catalyst application is probably (i.e. should be)
+structured in the recommended way (i.e., that generated by bootstrapping
+the application with the C<catalyst.pl> script, with a main directory
+under which is a C<lib/> directory for module files and a C<root/>
+directory for templates and static files). Thus, unless you break up
+this structure when deploying your app by moving the static files to a
+different location in your filesystem, you will need to use an Alias
+directive in Apache to point to the right place. You will then need to
+add a Directory block to give permission for Apache to serve these
+files. The final configuration will look something like this:
+
+    Alias /myapp/static /filesystem/path/to/MyApp/root/static
+    <Directory /filesystem/path/to/MyApp/root/static>
+        allow from all
+    </Directory>
+    <Location /myapp/static>
+        SetHandler default-handler
+    </Location>
+
+If you are running in a VirtualHost, you can just set the DocumentRoot
+location to the location of your root directory; see 
+L<Catalyst::Engine::Apache2::MP20>.
+
+=head1 PUBLIC METHODS
+
+=head2 serve_static_file $file_path
+
+Will serve the file located in $file_path statically. This is useful when
+you need to  autogenerate them if they don't exist, or they are stored in a model.
+
+    package MyApp::Controller::User;
+
+    sub curr_user_thumb : PathPart("my_thumbnail.png") {
+        my ( $self, $c ) = @_;
+        my $file_path = $c->user->picture_thumbnail_path;
+        $c->serve_static_file($file_path);
+    }
+
 =head1 INTERNAL EXTENDED METHODS
 
 Static::Simple extends the following steps in the Catalyst process.
@@ -464,8 +531,11 @@ Andy Grundman, <andy@hybridized.org>
 =head1 CONTRIBUTORS
 
 Marcus Ramberg, <mramberg@cpan.org>
+
 Jesse Sheidlower, <jester@panix.com>
 
+Guillermo Roditi, <groditi@cpan.org>
+
 =head1 THANKS
 
 The authors of Catalyst::Plugin::Static: