-# Copyright (C) 2016-2020 all contributors <meta@public-inbox.org>
+# Copyright (C) 2016-2021 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# This package can either be a PSGI response body for a static file
# functionality of nginx.
package PublicInbox::WwwStatic;
use strict;
+use v5.10.1;
use parent qw(Exporter);
-use bytes ();
use Fcntl qw(SEEK_SET O_RDONLY O_NONBLOCK);
use POSIX qw(strftime);
use HTTP::Date qw(time2str);
sub path_info_raw ($) {
my ($env) = @_;
my $sn = $env->{SCRIPT_NAME};
- my $re = $path_re_cache{$sn} ||= do {
+ my $re = $path_re_cache{$sn} //= do {
$sn = '/'.$sn unless index($sn, '/') == 0;
$sn =~ s!/\z!!;
qr!\A(?:https?://[^/]+)?\Q$sn\E(/[^\?\#]+)!;
my $path_info = $env->{PATH_INFO};
push @entries, '..' if $path_info ne '/';
for my $base (@entries) {
+ my @st = stat($fs_path . $base) or next; # unlikely
my $href = ascii_html(uri_escape_utf8($base));
my $name = ascii_html($base);
- my @st = stat($fs_path . $base) or next; # unlikely
- my ($gzipped, $uncompressed, $hsize);
- my $entry = '';
my $mtime = $st[9];
+ my ($entry, $hsize);
if (-d _) {
$href .= '/';
$name .= '/';
next;
}
# 54 = 80 - (SP length(strftime(%Y-%m-%d %k:%M)) SP human_size)
- $hsize = sprintf('% 8s', $hsize);
my $pad = 54 - length($name);
$pad = 1 if $pad <= 0;
- $entry .= qq(<a\nhref="$href">$name</a>) . (' ' x $pad);
- $mtime = strftime('%Y-%m-%d %k:%M', gmtime($mtime));
- $entry .= $mtime . $hsize;
+ $entry = qq(\n<a\nhref="$href">$name</a>) .
+ (' ' x $pad) .
+ strftime('%Y-%m-%d %k:%M', gmtime($mtime)) .
+ sprintf('% 8s', $hsize);
}
# filter out '.gz' files as long as the mtime matches the
delete(@other{keys %want_gz});
@entries = ((map { ${$dirs{$_}} } sort keys %dirs),
(map { ${$other{$_}} } sort keys %other));
-
my $path_info_html = ascii_html($path_info);
- my $h = [qw(Content-Type text/html Content-Length), undef];
- my $gzf = gzf_maybe($h, $env);
- $gzf->zmore("<html><head><title>Index of $path_info_html</title>" .
- ${$self->{style}} .
- "</head><body><pre>Index of $path_info_html</pre><hr><pre>\n");
- $gzf->zmore(join("\n", @entries));
- my $out = $gzf->zflush("</pre><hr></body></html>\n");
- $h->[3] = bytes::length($out);
- [ 200, $h, [ $out ] ]
+ my @h = qw(Content-Type text/html);
+ my $gzf = gzf_maybe(\@h, $env);
+ print { $gzf->zfh } '<html><head><title>Index of ', $path_info_html,
+ '</title>', ${$self->{style}}, '</head><body><pre>Index of ',
+ $path_info_html, '</pre><hr><pre>', @entries,
+ '</pre><hr></body></html>';
+ my $out = $gzf->zflush;
+ push @h, 'Content-Length', length($out);
+ [ 200, \@h, [ $out ] ]
}
sub call { # PSGI app endpoint