use MIME::Types;
use NEXT;
-our $VERSION = '0.06';
+our $VERSION = '0.09';
-__PACKAGE__->mk_classdata( qw/_mime_types/ );
+__PACKAGE__->mk_classdata( qw/_static_mime_types/ );
__PACKAGE__->mk_accessors( qw/_static_file
- _apache_mode
- _debug_message/ );
+ _static_apache_mode
+ _static_debug_message/ );
# prepare_action is used to first check if the request path is a static file.
# If so, we skip all other prepare_action steps to improve performance.
return if ( $c->_locate_static_file );
}
- return $c->NEXT::prepare_action(@_);
+ return $c->NEXT::ACTUAL::prepare_action(@_);
}
# dispatch takes the file found during prepare_action and serves it
sub dispatch {
my $c = shift;
- return undef if ( $c->res->status == 404 );
+ return if ( $c->res->status != 200 );
if ( $c->_static_file ) {
+ if ( $c->config->{static}->{no_logs} && $c->log->can('abort') ) {
+ $c->log->abort( 1 );
+ }
return $c->_serve_static;
}
else {
- return $c->NEXT::dispatch(@_);
+ return $c->NEXT::ACTUAL::dispatch(@_);
}
}
# display all log messages
if ( $c->config->{static}->{debug} && scalar @{$c->_debug_msg} ) {
- $c->log->debug( "Static::Simple: Serving " .
- join( " ", @{$c->_debug_msg} )
- );
+ $c->log->debug( "Static::Simple: " .
+ join( " ", @{$c->_debug_msg} ) );
}
# return DECLINED when under mod_perl
- if ( $c->config->{static}->{use_apache} && $c->_apache_mode ) {
- my $engine = $c->_apache_mode;
+ if ( $c->config->{static}->{use_apache} && $c->_static_apache_mode ) {
+ my $engine = $c->_static_apache_mode;
no strict 'subs';
if ( $engine == 13 ) {
return Apache::Constants::DECLINED;
return $c->finalize_headers;
}
- return $c->NEXT::finalize(@_);
+ return $c->NEXT::ACTUAL::finalize(@_);
}
sub setup {
$c->config->{static}->{dirs} ||= [];
$c->config->{static}->{include_path} ||= [ $c->config->{root} ];
$c->config->{static}->{mime_types} ||= {};
- $c->config->{static}->{use_apache} ||= 0;
+ $c->config->{static}->{ignore_extensions} ||= [ qw/tt html xhtml/ ];
+ $c->config->{static}->{ignore_dirs} ||= [];
+ $c->config->{static}->{use_apache} ||= 0;
$c->config->{static}->{debug} ||= $c->debug;
+ if ( ! defined $c->config->{static}->{no_logs} ) {
+ $c->config->{static}->{no_logs} = 1;
+ }
# load up a MIME::Types object, only loading types with
# at least 1 file extension
- $c->_mime_types( MIME::Types->new( only_complete => 1 ) );
+ $c->_static_mime_types( MIME::Types->new( only_complete => 1 ) );
+
# preload the type index hash so it's not built on the first request
- $c->_mime_types->create_type_index;
+ $c->_static_mime_types->create_type_index;
}
# Search through all included directories for the static file
my $dpaths;
my $count = 64; # maximum number of directories to search
+ DIR_CHECK:
while ( @ipaths && --$count) {
- my $dir = shift @ipaths || next;
+ my $dir = shift @ipaths || next DIR_CHECK;
if ( ref $dir eq 'CODE' ) {
eval { $dpaths = &$dir( $c ) };
$c->log->error( "Static::Simple: include_path error: " . $@ );
} else {
unshift( @ipaths, @$dpaths );
- next;
+ next DIR_CHECK;
}
} else {
$dir =~ s/\/$//xms;
if ( -d $dir && -f $dir . '/' . $path ) {
- $c->_debug_msg( $dir . "/" . $path )
+
+ # do we need to ignore the file?
+ for my $ignore ( @{ $c->config->{static}->{ignore_dirs} } ) {
+ $ignore =~ s{/$}{};
+ if ( $path =~ /^$ignore\// ) {
+ $c->_debug_msg( "Ignoring directory `$ignore`" )
+ if ( $c->config->{static}->{debug} );
+ next DIR_CHECK;
+ }
+ }
+
+ # do we need to ignore based on extension?
+ for my $ignore_ext
+ ( @{ $c->config->{static}->{ignore_extensions} } ) {
+ if ( $path =~ /.*\.${ignore_ext}$/ixms ) {
+ $c->_debug_msg( "Ignoring extension `$ignore_ext`" )
+ if ( $c->config->{static}->{debug} );
+ next DIR_CHECK;
+ }
+ }
+
+ $c->_debug_msg( 'Serving ' . $dir . '/' . $path )
if ( $c->config->{static}->{debug} );
return $c->_static_file( $dir . '/' . $path );
}
}
}
- return undef;
+ return;
}
sub _serve_static {
# check that Apache will serve the correct file
if ( $c->apache->document_root ne $c->config->{root} ) {
- $c->log->warn( "Static::Simple: Your Apache DocumentRoot"
- . " must be set to " . $c->config->{root}
- . " to use the Apache feature. Yours is"
- . " currently " . $c->apache->document_root
+ $c->log->warn( 'Static::Simple: Your Apache DocumentRoot'
+ . ' must be set to ' . $c->config->{root}
+ . ' to use the Apache feature. Yours is'
+ . ' currently ' . $c->apache->document_root
);
}
else {
- $c->_debug_msg( "DECLINED to Apache" )
+ $c->_debug_msg( 'DECLINED to Apache' )
if ( $c->config->{static}->{debug} );
- $c->_apache_mode( $engine );
- return undef;
+ $c->_static_apache_mode( $engine );
+ return;
}
}
}
# looks up the correct MIME type for the current file extension
sub _ext_to_type {
my $c = shift;
-
my $path = $c->req->path;
- my $type;
if ( $path =~ /.*\.(\S{1,})$/xms ) {
my $ext = $1;
my $user_types = $c->config->{static}->{mime_types};
- if ( $type = $user_types->{$ext}
- || $c->_mime_types->mimeTypeOf( $ext ) ) {
+ my $type = $user_types->{$ext}
+ || $c->_static_mime_types->mimeTypeOf( $ext );
+ if ( $type ) {
$c->_debug_msg( "as $type" )
if ( $c->config->{static}->{debug} );
return $type;
sub _debug_msg {
my ( $c, $msg ) = @_;
- if ( !defined $c->_debug_message ) {
- $c->_debug_message( [] );
+ if ( !defined $c->_static_debug_message ) {
+ $c->_static_debug_message( [] );
}
if ( $msg ) {
- push @{ $c->_debug_message }, $msg;
+ push @{ $c->_static_debug_message }, $msg;
}
- return $c->_debug_message;
+ return $c->_static_debug_message;
}
1;
MyApp->config->{static}. If you use any of these options, the module will
probably feel less "simple" to you!
-=over 4
+=head2 Aborting request logging
+
+Since Catalyst 5.50, there has been added support for dropping logging for a
+request. This is enabled by default for static files, as static requests tend
+to clutter the log output. However, if you want logging of static requests,
+you can enable it by setting MyApp->config->{static}->{no_logs} to 0.
-=item Forcing directories into static mode
+=head2 Forcing directories into static mode
Define a list of top-level directories beneath your 'root' directory that
should always be served in static mode. Regular expressions may be
qr/^(images|css)/,
];
-=item Including additional directories (experimental!)
+=head2 Including additional directories
You may specify a list of directories in which to search for your static
files. The directories will be searched in order and will return the first
die "No customer dir defined.";
}
}
+
+=head2 Ignoring certain types of files
+
+There are some file types you may not wish to serve as static files. Most
+important in this category are your raw template files. By default, files
+with the extensions tt, html, and xhtml will be ignored by Static::Simple in
+the interest of security. If you wish to define your own extensions to
+ignore, use the ignore_extensions option:
+
+ MyApp->config->{static}->{ignore_extensions} = [ qw/tt html xhtml/ ];
+
+=head2 Ignoring entire directories
+
+To prevent an entire directory from being served statically, you can use the
+ignore_dirs option. This option contains a list of relative directory paths
+to ignore. If using include_path, the path will be checked against every
+included path.
-=item Custom MIME types
+ MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ];
+
+For example, if combined with the above include_path setting, this
+ignore_dirs value will ignore the following directories if they exist:
+
+ /path/to/overlay/tmpl
+ /path/to/overlay/css
+ /dynamic/path/tmpl
+ /dynamic/path/css
+ /your/app/home/root/tmpl
+ /your/app/home/root/css
+
+=head2 Custom MIME types
To override or add to the default MIME types set by the MIME::Types module,
you may enter your own extension to MIME type mapping.
jpg => 'image/jpg',
png => 'image/png',
};
-
-=item Apache integration and performance
+
+=head2 Apache integration and performance
Optionally, when running under mod_perl, Static::Simple can return DECLINED
on static files to allow Apache to serve the file. A check is first done to
<Location /static>
SetHandler default-handler
</Location>
-
-=item Bypassing other plugins
+
+=head2 Bypassing other plugins
This plugin checks for a static file in the prepare_action stage. If the
request is for a static file, it will bypass all remaining prepare_action
Currently, work done by plugins in any other prepare method will execute
normally.
-=item Debugging information
+=head2 Debugging information
Enable additional debugging information printed in the Catalyst log. This
is automatically enabled when running Catalyst in -Debug mode.
MyApp->config->{static}->{debug} = 1;
-=back
-
=head1 SEE ALSO
L<Catalyst>, L<Catalyst::Plugin::Static>,
Andy Grundman, <andy@hybridized.org>
+=head1 CONTRIBUTORS
+
+Marcus Ramberg, <mramberg@cpan.org>
+
=head1 THANKS
The authors of Catalyst::Plugin::Static: