X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FStatic%2FSimple.pm;h=305dd61aeeb803f00a7f478c517a62ea602ef9b2;hb=46f893f9bae5216bb10b5c5605962987e1254132;hp=e15a9dea68570276bcc41656e82a71573db126ce;hpb=6e89d83c40a25202d31ac9f9d8386ddab1f1c0a4;p=catagits%2FCatalyst-Plugin-Static-Simple.git
diff --git a/lib/Catalyst/Plugin/Static/Simple.pm b/lib/Catalyst/Plugin/Static/Simple.pm
index e15a9de..305dd61 100644
--- a/lib/Catalyst/Plugin/Static/Simple.pm
+++ b/lib/Catalyst/Plugin/Static/Simple.pm
@@ -1,35 +1,45 @@
package Catalyst::Plugin::Static::Simple;
-use strict;
-use warnings;
-use base qw/Class::Accessor::Fast Class::Data::Inheritable/;
+use Moose::Role;
use File::stat;
use File::Spec ();
use IO::File ();
use MIME::Types ();
+use MooseX::Types::Moose qw/ArrayRef Str/;
+use namespace::autoclean;
-our $VERSION = '0.20';
+our $VERSION = '0.28';
-__PACKAGE__->mk_accessors( qw/_static_file _static_debug_message/ );
+has _static_file => ( is => 'rw' );
+has _static_debug_message => ( is => 'rw', isa => ArrayRef[Str] );
-sub prepare_action {
+before prepare_action => sub {
my $c = shift;
my $path = $c->req->path;
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' )
@@ -42,21 +52,19 @@ 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::ACTUAL::prepare_action(@_);
-}
+};
-sub dispatch {
+override dispatch => sub {
my $c = shift;
-
+
return if ( $c->res->status != 200 );
-
+
if ( $c->_static_file ) {
if ( $c->config->{static}{no_logs} && $c->log->can('abort') ) {
$c->log->abort( 1 );
@@ -64,32 +72,24 @@ sub dispatch {
return $c->_serve_static;
}
else {
- return $c->NEXT::ACTUAL::dispatch(@_);
+ return super;
}
-}
+};
-sub finalize {
+before finalize => sub {
my $c = shift;
-
+
# display all log messages
if ( $c->config->{static}{debug} && scalar @{$c->_debug_msg} ) {
$c->log->debug( 'Static::Simple: ' . join q{ }, @{$c->_debug_msg} );
}
-
- return $c->NEXT::ACTUAL::finalize(@_);
-}
+};
-sub setup {
+before setup_finalize => sub {
my $c = shift;
-
- $c->NEXT::setup(@_);
-
- if ( Catalyst->VERSION le '5.33' ) {
- require File::Slurp;
- }
-
+
my $config = $c->config->{static} ||= {};
-
+
$config->{dirs} ||= [];
$config->{include_path} ||= [ $c->config->{root} ];
$config->{mime_types} ||= {};
@@ -98,33 +98,33 @@ 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;
-}
+};
# Search through all included directories for the static file
# 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->{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 ($@) {
@@ -136,7 +136,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?
@@ -148,7 +148,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 ) {
@@ -158,20 +158,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;
@@ -180,24 +180,16 @@ 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;
}
@@ -205,7 +197,7 @@ 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};
@@ -224,12 +216,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->{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};
@@ -250,15 +242,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;
}
@@ -271,8 +263,9 @@ Catalyst::Plugin::Static::Simple - Make serving static pages painless.
=head1 SYNOPSIS
- use Catalyst;
- MyApp->setup( qw/Static::Simple/ );
+ package MyApp;
+ use Catalyst qw/ Static::Simple /;
+ MyApp->setup;
# 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
@@ -296,6 +289,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
@@ -340,10 +345,14 @@ 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->{static}->{dirs} = [
- 'static',
- qr/^(images|css)/,
- ];
+ MyApp->config(
+ static => {
+ dirs => [
+ 'static',
+ qr/^(images|css)/,
+ ],
+ }
+ );
=head2 Including additional directories
@@ -353,19 +362,23 @@ 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->{static}->{include_path} = [
- '/path/to/overlay',
- \&incpath_generator,
- MyApp->config->{root}
- ];
-
+ 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
@@ -376,14 +389,14 @@ For example:
sub incpath_generator {
my $c = shift;
-
+
if ( $c->session->{customer_dir} ) {
return [ $c->session->{customer_dir} ];
} else {
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.
@@ -393,9 +406,12 @@ 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->{static}->{ignore_extensions}
- = [ qw/html asp php/ ];
-
+ 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
@@ -403,8 +419,12 @@ 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->{static}->{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:
@@ -413,17 +433,21 @@ 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->{static}->{mime_types} = {
- jpg => 'image/jpg',
- png => 'image/png',
- };
+ MyApp->config(
+ static => {
+ mime_types => {
+ jpg => 'image/jpg',
+ png => 'image/png',
+ },
+ },
+ );
=head2 Compatibility with other plugins
@@ -436,8 +460,12 @@ 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->{static}->{debug} = 1;
-
+ MyApp->config(
+ static => {
+ debug => 1,
+ },
+ );
+
=head1 USING WITH APACHE
While Static::Simple will work just fine serving files through Catalyst
@@ -475,6 +503,10 @@ files. The final configuration will look something like this:
SetHandler default-handler
+If you are running in a VirtualHost, you can just set the DocumentRoot
+location to the location of your root directory; see
+L.
+
=head1 PUBLIC METHODS
=head2 serve_static_file $file_path
@@ -494,7 +526,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
@@ -516,7 +548,7 @@ C initializes all default values.
=head1 SEE ALSO
-L, L,
+L, L,
L
=head1 AUTHOR
@@ -531,6 +563,12 @@ Jesse Sheidlower,
Guillermo Roditi,
+Florian Ragwitz,
+
+Tomas Doran,
+
+Justin Wheeler (dnm)
+
=head1 THANKS
The authors of Catalyst::Plugin::Static:
@@ -545,6 +583,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.