Any-Daemon-HTTP
view release on metacpan or search on metacpan
lib/Any/Daemon/HTTP/Directory.pm view on Meta::CPAN
open my $fh, '<:raw', $fn
or return HTTP::Response->new(HTTP_FORBIDDEN);
my ($dev, $inode, $mtime) = (stat $fh)[0,1,9];
my $etag = "$dev-$inode-$mtime";
my $has_etag = $req->header('If-None-Match');
return HTTP::Response->new(HTTP_NOT_MODIFIED, 'match etag')
if defined $has_etag && $has_etag eq $etag;
my $has_mtime = $req->if_modified_since;
return HTTP::Response->new(HTTP_NOT_MODIFIED, 'unchanged')
if defined $has_mtime && $has_mtime >= $mtime;
my $head = HTTP::Headers->new;
my $ct;
if(my $mime = $mimetypes->mimeTypeOf($fn))
{ $ct = $mime->type;
$ct .= '; charset='.$self->charset if $mime->isAscii;
}
else
{ $ct = 'binary/octet-stream';
}
$head->content_type($ct);
$head->last_modified($mtime);
$head->header(ETag => $etag);
local $/;
HTTP::Response->new(HTTP_OK, undef, $head, <$fh>);
}
sub _list_response($$$)
{ my ($self, $req, $uri, $dir) = @_;
no warnings 'uninitialized';
my $list = $self->list($dir);
my $now = localtime;
my @rows;
push @rows, <<__UP if $dir ne '/';
<tr><td colspan="5"> </td><td><a href="../">(up)</a></td></tr>
__UP
foreach my $item (sort keys %$list)
{ my $d = $list->{$item};
my $symdest = $d->{is_symlink} ? "→ $d->{symlink_dest}" : "";
push @rows, <<__ROW;
<tr><td>$d->{flags}</td>
<td>$d->{user}</td>
<td>$d->{group}</td>
<td align="right">$d->{size_nice}</td>
<td>$d->{mtime_nice}</td>
<td><a href="$d->{name}">$d->{name}</a>$symdest</td></tr>
__ROW
}
local $" = "\n";
my $content = encode 'utf8', <<__PAGE;
<html><head><title>$dir</title></head>
<style>TD { padding: 0 10px; }</style>
<body>
<h1>Directory $dir</h1>
<table>
@rows
</table>
<p><i>Generated $now</i></p>
</body></html>
__PAGE
HTTP::Response->new(HTTP_OK, undef
, ['Content-Type' => 'text/html; charset='.$self->charset]
, $content
);
}
my %filetype =
( &S_IFSOCK => 's', &S_IFLNK => 'l', &S_IFREG => '-', &S_IFBLK => 'b'
, &S_IFDIR => 'd', &S_IFCHR => 'c', &S_IFIFO => 'p');
my @flags = ('---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx');
my @stat_fields =
qw/dev ino mode nlink uid gid rdev size atime mtime ctime blksize blocks/;
sub list($@)
{ my ($self, $dirname, %opts) = @_;
opendir my $from_dir, $dirname
or return;
my $names = $opts{names} || qr/^[^.]/;
my $prefilter
= ref $names eq 'Regexp' ? sub { $_[0] =~ $names }
: ref $names eq 'CODE' ? $names
: panic "::Directory::list(names) must be regexp or code, not $names";
my $postfilter = $opts{filter} || sub {1};
ref $postfilter eq 'CODE'
or panic "::Directory::list(filter) must be code, not $postfilter";
my $hide_symlinks = $opts{hide_symlinks};
my (%dirlist, %users, %groups);
foreach my $name (grep $prefilter->($_), readdir $from_dir)
{ my $path = $dirname.$name;
my %d = (name => $name, path => $path);
@d{@stat_fields}
= $hide_symlinks ? stat($path) : lstat($path);
if(!$hide_symlinks && -l _)
{ @d{qw/kind is_symlink /} = ('SYMLINK', 1)}
elsif(-d _) { @d{qw/kind is_directory/} = ('DIRECTORY',1)}
elsif(-f _) { @d{qw/kind is_file /} = ('FILE', 1)}
else { @d{qw/kind is_other /} = ('OTHER', 1)}
$postfilter->(\%d)
or next;
( run in 0.698 second using v1.01-cache-2.11-cpan-97f6503c9c8 )