X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FStatic%2FSimple.pm;h=719a4708774ec09057f9a87500bdf04591647cb0;hb=7e7cdb8e775b76d8ac27830bba82287900bd5ecf;hp=caf3a0e39967e17abd53053488404d6564d64324;hpb=b6fdf01ddaef7d17127a1a5a4ab1396808e305b5;p=catagits%2FCatalyst-Plugin-Static-Simple.git diff --git a/lib/Catalyst/Plugin/Static/Simple.pm b/lib/Catalyst/Plugin/Static/Simple.pm index caf3a0e..719a470 100644 --- a/lib/Catalyst/Plugin/Static/Simple.pm +++ b/lib/Catalyst/Plugin/Static/Simple.pm @@ -9,30 +9,37 @@ use IO::File (); use MIME::Types (); use MRO::Compat; -our $VERSION = '0.21'; +our $VERSION = '0.26'; __PACKAGE__->mk_accessors( qw/_static_file _static_debug_message/ ); -my $CONFIG_KEY = "Plugin::Static::Simple"; - sub prepare_action { my $c = shift; my $path = $c->req->path; - my $config = $c->config->{$CONFIG_KEY} ||= $c->config->{static}; - + my $config = $c->config->{static}; + $path =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; # is the URI in a static-defined path? foreach my $dir ( @{ $config->{dirs} } ) { my $dir_re = quotemeta $dir; - + # 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': $@" ); + + my $re; + + if ( $dir =~ m{^qr/}xms ) { + $re = eval $dir; + + if ($@) { + $c->error( "Error compiling static dir regex '$dir': $@" ); + } + } + else { + $re = qr{^${dir_re}/}; } + if ( $path =~ $re ) { if ( $c->_locate_static_file( $path, 1 ) ) { $c->_debug_msg( 'from static directory' ) @@ -45,23 +52,23 @@ sub prepare_action { } } } - + # Does the path have an extension? if ( $path =~ /.*\.(\S{1,})$/xms ) { # and does it exist? $c->_locate_static_file( $path ); } - + return $c->next::method(@_); } sub dispatch { my $c = shift; - + return if ( $c->res->status != 200 ); - + if ( $c->_static_file ) { - if ( $c->config->{$CONFIG_KEY}{no_logs} && $c->log->can('abort') ) { + if ( $c->config->{static}{no_logs} && $c->log->can('abort') ) { $c->log->abort( 1 ); } return $c->_serve_static; @@ -73,26 +80,22 @@ sub dispatch { sub finalize { my $c = shift; - + # display all log messages - if ( $c->config->{$CONFIG_KEY}{debug} && scalar @{$c->_debug_msg} ) { + if ( $c->config->{static}{debug} && scalar @{$c->_debug_msg} ) { $c->log->debug( 'Static::Simple: ' . join q{ }, @{$c->_debug_msg} ); } - + return $c->next::method(@_); } sub setup { my $c = shift; - + $c->maybe::next::method(@_); - - if ( Catalyst->VERSION le '5.33' ) { - require File::Slurp; - } - - my $config = $c->config->{$CONFIG_KEY} ||= {}; - + + my $config = $c->config->{static} ||= {}; + $config->{dirs} ||= []; $config->{include_path} ||= [ $c->config->{root} ]; $config->{mime_types} ||= {}; @@ -101,11 +104,11 @@ sub setup { $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 $config->{mime_types_obj} = MIME::Types->new( only_complete => 1 ); - + # preload the type index hash so it's not built on the first request $config->{mime_types_obj}->create_type_index; } @@ -114,20 +117,20 @@ sub setup { # Based on Template Toolkit INCLUDE_PATH code sub _locate_static_file { my ( $c, $path, $in_static_dir ) = @_; - + $path = File::Spec->catdir( - File::Spec->no_upwards( File::Spec->splitdir( $path ) ) + File::Spec->no_upwards( File::Spec->splitdir( $path ) ) ); - - my $config = $c->config->{$CONFIG_KEY}; + + my $config = $c->config->{static}; my @ipaths = @{ $config->{include_path} }; my $dpaths; my $count = 64; # maximum number of directories to search - + DIR_CHECK: while ( @ipaths && --$count) { my $dir = shift @ipaths || next DIR_CHECK; - + if ( ref $dir eq 'CODE' ) { eval { $dpaths = &$dir( $c ) }; if ($@) { @@ -139,7 +142,7 @@ sub _locate_static_file { } else { $dir =~ s/(\/|\\)$//xms; if ( -d $dir && -f $dir . '/' . $path ) { - + # Don't ignore any files in static dirs defined with 'dirs' unless ( $in_static_dir ) { # do we need to ignore the file? @@ -151,7 +154,7 @@ sub _locate_static_file { next DIR_CHECK; } } - + # do we need to ignore based on extension? for my $ignore_ext ( @{ $config->{ignore_extensions} } ) { if ( $path =~ /.*\.${ignore_ext}$/ixms ) { @@ -161,20 +164,20 @@ sub _locate_static_file { } } } - + $c->_debug_msg( 'Serving ' . $dir . '/' . $path ) if $config->{debug}; return $c->_static_file( $dir . '/' . $path ); } } } - + return; } sub _serve_static { my $c = shift; - + my $full_path = shift || $c->_static_file; my $type = $c->_ext_to_type( $full_path ); my $stat = stat $full_path; @@ -183,32 +186,24 @@ sub _serve_static { $c->res->headers->content_length( $stat->size ); $c->res->headers->last_modified( $stat->mtime ); - if ( Catalyst->VERSION le '5.33' ) { - # old File::Slurp method - my $content = File::Slurp::read_file( $full_path ); - $c->res->body( $content ); + my $fh = IO::File->new( $full_path, 'r' ); + if ( defined $fh ) { + binmode $fh; + $c->res->body( $fh ); } else { - # new method, pass an IO::File object to body - my $fh = IO::File->new( $full_path, 'r' ); - if ( defined $fh ) { - binmode $fh; - $c->res->body( $fh ); - } - else { - Catalyst::Exception->throw( - message => "Unable to open $full_path for reading" ); - } + Catalyst::Exception->throw( + message => "Unable to open $full_path for reading" ); } - + return 1; } sub serve_static_file { my ( $c, $full_path ) = @_; - my $config = $c->config->{$CONFIG_KEY} ||= {}; - + my $config = $c->config->{static} ||= {}; + if ( -e $full_path ) { $c->_debug_msg( "Serving static file: $full_path" ) if $config->{debug}; @@ -227,12 +222,12 @@ sub serve_static_file { # looks up the correct MIME type for the current file extension sub _ext_to_type { my ( $c, $full_path ) = @_; - - my $config = $c->config->{$CONFIG_KEY}; - + + my $config = $c->config->{static}; + if ( $full_path =~ /.*\.(\S{1,})$/xms ) { my $ext = $1; - my $type = $config->{mime_types}{$ext} + my $type = $config->{mime_types}{$ext} || $config->{mime_types_obj}->mimeTypeOf( $ext ); if ( $type ) { $c->_debug_msg( "as $type" ) if $config->{debug}; @@ -253,15 +248,15 @@ sub _ext_to_type { sub _debug_msg { my ( $c, $msg ) = @_; - + if ( !defined $c->_static_debug_message ) { $c->_static_debug_message( [] ); } - + if ( $msg ) { push @{ $c->_static_debug_message }, $msg; } - + return $c->_static_debug_message; } @@ -300,6 +295,18 @@ through Catalyst. Note that actions mapped to paths using periods (.) will still operate properly. +If the plugin can not find the file, the request is dispatched to your +application instead. This means you are responsible for generating a +C<404> error if your applicaton can not process the request: + + # handled by static::simple, not dispatched to your application + /images/exists.png + + # static::simple will not find the file and let your application + # handle the request. You are responsible for generating a file + # or returning a 404 error + /images/does_not_exist.png + Though Static::Simple is designed to work out-of-the-box, you can tweak the operation by adding various configuration options. In a production environment, you will probably want to use your webserver to deliver @@ -327,8 +334,8 @@ Logging of static files is turned off by default. =head1 ADVANCED CONFIGURATION Configuration is completely optional and is specified within -Cconfig-E{'Plugin::Static::Simple'}>. If you use any of these -options, this module will probably feel less "simple" to you! +Cconfig-E{static}>. If you use any of these options, +this module will probably feel less "simple" to you! =head2 Enabling request logging @@ -336,7 +343,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 -Cconfig-E{'Plugin::Static::Simple'}-E{logging}> to 1. +Cconfig-E{static}-E{logging}> to 1. =head2 Forcing directories into static mode @@ -344,7 +351,7 @@ Define a list of top-level directories beneath your 'root' directory that should always be served in static mode. Regular expressions may be specified using C. - MyApp->config->{'Plugin::Static::Simple'}->{dirs} = [ + MyApp->config->{static}->{dirs} = [ 'static', qr/^(images|css)/, ]; @@ -357,19 +364,19 @@ first file found. Note that your root directory is B automatically added to the search path when you specify an C. You should use Cconfig-E{root}> to add it. - MyApp->config->{'Plugin::Static::Simple'}->{include_path} = [ + MyApp->config->{static}->{include_path} = [ '/path/to/overlay', \&incpath_generator, MyApp->config->{root} ]; - + With the above setting, a request for the file C will search for the following files, returning the first one found: /path/to/overlay/images/logo.jpg /dynamic/path/images/logo.jpg /your/app/home/root/images/logo.jpg - + The include path can contain a subroutine reference to dynamically return a list of available directories. This method will receive the C<$c> object as a parameter and should return a reference to a list of directories. Errors can @@ -387,7 +394,7 @@ For example: 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. @@ -397,9 +404,9 @@ C will be ignored by Static::Simple in the interest of security. If you wish to define your own extensions to ignore, use the C option: - MyApp->config->{'Plugin::Static::Simple'}->{ignore_extensions} + MyApp->config->{static}->{ignore_extensions} = [ qw/html asp php/ ]; - + =head2 Ignoring entire directories To prevent an entire directory from being served statically, you can use @@ -407,8 +414,8 @@ the C option. This option contains a list of relative directory paths to ignore. If using C, the path will be checked against every included path. - MyApp->config->{'Plugin::Static::Simple'}->{ignore_dirs} = [ qw/tmpl css/ ]; - + MyApp->config->{static}->{ignore_dirs} = [ qw/tmpl css/ ]; + For example, if combined with the above C setting, this C value will ignore the following directories if they exist: @@ -417,14 +424,14 @@ C value will ignore the following directories if they exist: /dynamic/path/tmpl /dynamic/path/css /your/app/home/root/tmpl - /your/app/home/root/css + /your/app/home/root/css =head2 Custom MIME types To override or add to the default MIME types set by the L module, you may enter your own extension to MIME type mapping. - MyApp->config->{'Plugin::Static::Simple'}->{mime_types} = { + MyApp->config->{static}->{mime_types} = { jpg => 'image/jpg', png => 'image/png', }; @@ -440,8 +447,8 @@ many compatibility issues with other plugins. Enable additional debugging information printed in the Catalyst log. This is automatically enabled when running Catalyst in -Debug mode. - MyApp->config->{'Plugin::Static::Simple'}->{debug} = 1; - + MyApp->config->{static}->{debug} = 1; + =head1 USING WITH APACHE While Static::Simple will work just fine serving files through Catalyst @@ -480,7 +487,7 @@ files. The final configuration will look something like this: If you are running in a VirtualHost, you can just set the DocumentRoot -location to the location of your root directory; see +location to the location of your root directory; see L. =head1 PUBLIC METHODS @@ -502,7 +509,7 @@ you need to autogenerate them if they don't exist, or they are stored in a mode Static::Simple extends the following steps in the Catalyst process. -=head2 prepare_action +=head2 prepare_action C is used to first check if the request path is a static file. If so, we skip all other C steps to improve @@ -524,7 +531,7 @@ C initializes all default values. =head1 SEE ALSO -L, L, +L, L, L =head1 AUTHOR @@ -539,6 +546,12 @@ Jesse Sheidlower, Guillermo Roditi, +Florian Ragwitz, + +Tomas Doran, + +Justin Wheeler (dnm) + =head1 THANKS The authors of Catalyst::Plugin::Static: @@ -553,6 +566,12 @@ For the include_path code from Template Toolkit: =head1 COPYRIGHT +Copyright (c) 2005 - 2009 +the Catalyst::Plugin::Static::Simple L and L +as listed above. + +=head1 LICENSE + This program is free software, you can redistribute it and/or modify it under the same terms as Perl itself.