Catalyst-Plugin-ServeFile
view release on metacpan or search on metacpan
lib/Catalyst/Plugin/ServeFile.pm view on Meta::CPAN
package Catalyst::Plugin::ServeFile;
use Moo::Role;
use Plack::Util ();
use Plack::MIME ();
use HTTP::Date ();
use File::Spec ();
use Cwd ();
our $VERSION = '0.004';
# We break this out since its the first step in making this plugin 'pluggable'
# in terms of where the static assets are found. Maybe we might have a
# $get_asset_from_database someday
my $get_asset_from_filesystem = sub {
my ($c, $full_path) = @_;
# Does it exist?
unless(-f $full_path) {
$c->log->debug("Static File at '$full_path' not found!") if $c->debug;
return;
}
open(my $fh, '<', $full_path) || do {
$c->log->debug("Static file at '$full_path' cannot be open'd for read with error: $@")
if $c->debug;
return;
};
my @stat = stat($full_path);
unless(@stat) {
$c->log->debug("Static file at '$full_path' cannot be stat'd with error: $@")
if $c->debug;
return;
}
Plack::Util::set_io_path($fh, Cwd::realpath($full_path)); # Support Xsendfile
return ($fh, @stat);
};
sub serve_file {
my $c = shift;
my $options = ref($_[-1]) ? pop @_ : +{};
my $config = $c->config->{'Plugin::ServeFile'} || +{};
my %settings = (%$config, %$options);
$c->log->abort(1) unless $settings{show_log};
my $root = $settings{root} || $c->config->{root};
my $file_proto = File::Spec->catdir(
File::Spec->no_upwards(
map { File::Spec->splitdir($_) } @_ ));
my $full_path = File::Spec->catfile($root, $file_proto);
my $content_type = Plack::MIME->mime_type($full_path) || 'application/octet';
if(my $allowed_content_types = $settings{allowed_content_types}) {
unless(scalar( grep { lc($content_type) eq lc($_) } @$allowed_content_types)) {
$c->log->debug("Static file has disallowed content-type of '$content_type'") if $c->debug;
return;
}
}
my ($fh, @stat) = $c->$get_asset_from_filesystem($full_path);
return unless $fh;
if ($content_type =~ m!^text/!) {
my $encoding = $settings{encoding} || "utf-8";
$content_type .= "; charset=$encoding";
}
$c->log->debug("Serving Static File: $full_path") if $c->debug;
my $status = $settings{status} || $settings{code} || 200;
$c->res->status($status);
$c->res->headers->header(
'Content-Type' => $content_type,
'Content-Length' => $stat[7],
'Last-Modified' => HTTP::Date::time2str( $stat[9] ),
'Cache-control' => 'public');
$c->res->body($fh);
return $fh;
}
1;
( run in 0.489 second using v1.01-cache-2.11-cpan-39bf76dae61 )