]> Sergey Matveev's repositories - public-inbox.git/blob - t/www_static.t
No ext_urls
[public-inbox.git] / t / www_static.t
1 # Copyright (C) 2019-2021 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3 use strict;
4 use warnings;
5 use Test::More;
6 use PublicInbox::TestCommon;
7 my ($tmpdir, $for_destroy) = tmpdir();
8 my @mods = qw(HTTP::Request::Common Plack::Test URI::Escape);
9 require_mods(@mods, 'IO::Uncompress::Gunzip');
10 use_ok $_ foreach @mods;
11 use_ok 'PublicInbox::WwwStatic';
12
13 my $app = sub {
14         my $ws = PublicInbox::WwwStatic->new(docroot => $tmpdir, @_);
15         sub { $ws->call(shift) };
16 };
17
18 test_psgi($app->(), sub {
19         my $cb = shift;
20         my $res = $cb->(GET('/'));
21         is($res->code, 404, '404 on "/" by default');
22         open my $fh, '>', "$tmpdir/index.html" or die;
23         print $fh 'hi' or die;
24         close $fh or die;
25         $res = $cb->(GET('/'));
26         is($res->code, 200, '200 with index.html');
27         is($res->content, 'hi', 'default index.html returned');
28         $res = $cb->(HEAD('/'));
29         is($res->code, 200, '200 on HEAD /');
30         is($res->content, '', 'no content');
31         is($res->header('Content-Length'), '2', 'content-length set');
32         like($res->header('Content-Type'), qr!^text/html\b!,
33                 'content-type is html');
34 });
35
36 test_psgi($app->(autoindex => 1, index => []), sub {
37         my $cb = shift;
38         my $res = $cb->(GET('/'));
39         my $updir = 'href="../">../</a>';
40         is($res->code, 200, '200 with autoindex default');
41         my $ls = $res->content;
42         like($ls, qr/index\.html/, 'got listing with index.html');
43         ok(index($ls, $updir) < 0, 'no updir at /');
44         mkdir("$tmpdir/dir") or die;
45         rename("$tmpdir/index.html", "$tmpdir/dir/index.html") or die;
46
47         $res = $cb->(GET('/dir/'));
48         is($res->code, 200, '200 with autoindex for dir/');
49         $ls = $res->content;
50         ok(index($ls, $updir) > 0, 'updir at /dir/');
51
52         for my $up (qw(/../ .. /dir/.. /dir/../)) {
53                 is($cb->(GET($up))->code, 403, "`$up' traversal rejected");
54         }
55
56         $res = $cb->(GET('/dir'));
57         is($res->code, 302, '302 w/o slash');
58         like($res->header('Location'), qr!://[^/]+/dir/\z!,
59                 'redirected w/ slash');
60
61         rename("$tmpdir/dir/index.html", "$tmpdir/dir/foo") or die;
62         link("$tmpdir/dir/foo", "$tmpdir/dir/foo.gz") or die;
63         $res = $cb->(GET('/dir/'));
64         unlike($res->content, qr/>foo\.gz</,
65                 '.gz file hidden if mtime matches uncompressed');
66         like($res->content, qr/>foo</, 'uncompressed foo shown');
67
68         $res = $cb->(GET('/dir/foo/bar'));
69         is($res->code, 404, 'using file as dir fails');
70
71         unlink("$tmpdir/dir/foo") or die;
72         $res = $cb->(GET('/dir/'));
73         like($res->content, qr/>foo\.gz</,
74                 '.gz shown when no uncompressed version exists');
75
76         open my $fh, '>', "$tmpdir/dir/foo" or die;
77         print $fh "uncompressed\n" or die;
78         close $fh or die;
79         utime(0, 0, "$tmpdir/dir/foo") or die;
80         $res = $cb->(GET('/dir/'));
81         my $html = $res->content;
82         like($html, qr/>foo</, 'uncompressed foo shown');
83         like($html, qr/>foo\.gz</, 'gzipped foo shown on mtime mismatch');
84
85         $res = $cb->(GET('/dir/foo'));
86         is($res->content, "uncompressed\n",
87                 'got uncompressed on mtime mismatch');
88
89         utime(0, 0, "$tmpdir/dir/foo.gz") or die;
90         my $get = GET('/dir/foo');
91         $get->header('Accept-Encoding' => 'gzip');
92         $res = $cb->($get);
93         is($res->content, "hi", 'got compressed on mtime match');
94
95         $get = GET('/dir/');
96         $get->header('Accept-Encoding' => 'gzip');
97         $res = $cb->($get);
98         my $in = $res->content;
99         my $out = '';
100         IO::Uncompress::Gunzip::gunzip(\$in => \$out);
101         like($out, qr/\A<html>/, 'got HTML start after gunzip');
102         like($out, qr{</html>$}, 'got HTML end after gunzip');
103 });
104
105 done_testing();