package Plack::App::Directory; use parent qw(Plack::App::File); use strict; use warnings; use Plack::Util; use HTTP::Date; use Plack::MIME; use DirHandle; use URI::Escape; use Plack::Request; # Stolen from rack/directory.rb my $dir_file = "%s%s%s%s"; my $dir_page = < %s

%s


%s
Name Size Type Last Modified

PAGE sub should_handle { my($self, $file) = @_; return -d $file || -f $file; } sub return_dir_redirect { my ($self, $env) = @_; my $uri = Plack::Request->new($env)->uri; return [ 301, [ 'Location' => $uri . '/', 'Content-Type' => 'text/plain', 'Content-Length' => 8, ], [ 'Redirect' ], ]; } sub serve_path { my($self, $env, $dir) = @_; if (-f $dir) { return $self->SUPER::serve_path($env, $dir); } my $dir_url = $env->{SCRIPT_NAME} . $env->{PATH_INFO}; if ($dir_url !~ m{/$}) { return $self->return_dir_redirect($env); } my @files = ([ "../", "Parent Directory", '', '', '' ]); my $dh = DirHandle->new($dir); my @children; while (defined(my $ent = $dh->read)) { next if $ent eq '.' or $ent eq '..'; push @children, $ent; } for my $basename (sort { $a cmp $b } @children) { my $file = "$dir/$basename"; my $url = $dir_url . $basename; my $is_dir = -d $file; my @stat = stat _; $url = join '/', map {uri_escape($_)} split m{/}, $url; if ($is_dir) { $basename .= "/"; $url .= "/"; } my $mime_type = $is_dir ? 'directory' : ( Plack::MIME->mime_type($file) || 'text/plain' ); push @files, [ $url, $basename, $stat[7], $mime_type, HTTP::Date::time2str($stat[9]) ]; } my $path = Plack::Util::encode_html("Index of $env->{PATH_INFO}"); my $files = join "\n", map { my $f = $_; sprintf $dir_file, map Plack::Util::encode_html($_), @$f; } @files; my $page = sprintf $dir_page, $path, $path, $files; return [ 200, ['Content-Type' => 'text/html; charset=utf-8'], [ $page ] ]; } 1; __END__ =head1 NAME Plack::App::Directory - Serve static files from document root with directory index =head1 SYNOPSIS # app.psgi use Plack::App::Directory; my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })->to_app; =head1 DESCRIPTION This is a static file server PSGI application with directory index a la Apache's mod_autoindex. =head1 CONFIGURATION =over 4 =item root Document root directory. Defaults to the current directory. =back =head1 AUTHOR Tatsuhiko Miyagawa =head1 SEE ALSO L =cut