]> Sergey Matveev's repositories - public-inbox.git/blob - t/httpd-corner.psgi
t/httpd-unix: eliminate some busy waits
[public-inbox.git] / t / httpd-corner.psgi
1 # Copyright (C) all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3 # corner case tests for the generic PSGI server
4 # Usage: plackup [OPTIONS] /path/to/this/file
5 use v5.12;
6 use Plack::Builder;
7 require Digest::SHA;
8 if (defined(my $f = $ENV{TEST_OPEN_FIFO})) {
9         open my $fh, '>', $f or die "open($f): $!";
10         say $fh 'hi';
11         close $fh;
12 }
13
14 END {
15         if (defined(my $f = $ENV{TEST_EXIT_FIFO})) {
16                 open my $fh, '>', $f or die "open($f): $!";
17                 say $fh "bye from $$";
18                 close $fh;
19         }
20 }
21
22 my $pi_config = $ENV{PI_CONFIG} // 'unset'; # capture ASAP
23 my $app = sub {
24         my ($env) = @_;
25         my $path = $env->{PATH_INFO};
26         my $in = $env->{'psgi.input'};
27         my $actual = -s $in;
28         my $code = 500;
29         my $h = [ 'Content-Type' => 'text/plain' ];
30         my $body = [];
31         if ($path eq '/sha1') {
32                 my $sha1 = Digest::SHA->new('SHA-1');
33                 my $buf;
34                 while (1) {
35                         my $r = $in->read($buf, 4096);
36                         die "read err: $!" unless defined $r;
37                         last if $r == 0;
38                         $sha1->add($buf);
39                 }
40                 $code = 200;
41                 push @$body, $sha1->hexdigest;
42         } elsif (my $fifo = $env->{HTTP_X_CHECK_FIFO}) {
43                 if ($path eq '/slow-header') {
44                         return sub {
45                                 open my $f, '<', $fifo or
46                                                 die "open $fifo: $!\n";
47                                 local $/ = "\n";
48                                 my @r = <$f>;
49                                 $_[0]->([200, $h, \@r ]);
50                         };
51                 } elsif ($path eq '/slow-body') {
52                         return sub {
53                                 my $fh = $_[0]->([200, $h]);
54                                 open my $f, '<', $fifo or
55                                                 die "open $fifo: $!\n";
56                                 local $/ = "\n";
57                                 while (defined(my $l = <$f>)) {
58                                         $fh->write($l);
59                                 }
60                                 $fh->close;
61                         };
62                 }
63         } elsif ($path eq '/host-port') {
64                 $code = 200;
65                 push @$body, "$env->{REMOTE_ADDR} $env->{REMOTE_PORT}";
66         } elsif ($path eq '/callback') {
67                 return sub {
68                         my ($res) = @_;
69                         my $buf = "hello world\n";
70                         push @$h, 'Content-Length', length($buf);
71                         my $fh = $res->([200, $h]);
72                         $fh->write($buf);
73                         $fh->close;
74                 }
75         } elsif ($path eq '/empty') {
76                 $code = 200;
77         } elsif ($path eq '/getline-die') {
78                 $code = 200;
79                 $body = Plack::Util::inline_object(
80                         getline => sub { die 'GETLINE FAIL' },
81                         close => sub { die 'CLOSE FAIL' },
82                 );
83         } elsif ($path eq '/close-die') {
84                 $code = 200;
85                 $body = Plack::Util::inline_object(
86                         getline => sub { undef },
87                         close => sub { die 'CLOSE FAIL' },
88                 );
89         } elsif ($path eq '/async-big') {
90                 require PublicInbox::Qspawn;
91                 open my $null, '>', '/dev/null' or die;
92                 my $rdr = { 2 => fileno($null) };
93                 my $cmd = [qw(dd if=/dev/zero count=30 bs=1024k)];
94                 my $qsp = PublicInbox::Qspawn->new($cmd, undef, $rdr);
95                 return $qsp->psgi_return($env, undef, sub {
96                         my ($r, $bref) = @_;
97                         # make $rd_hdr retry sysread + $parse_hdr in Qspawn:
98                         return until length($$bref) > 8000;
99                         close $null;
100                         [ 200, [ qw(Content-Type application/octet-stream) ]];
101                 });
102         } elsif ($path eq '/psgi-return-gzip') {
103                 require PublicInbox::Qspawn;
104                 require PublicInbox::GzipFilter;
105                 my $cmd = [qw(echo hello world)];
106                 my $qsp = PublicInbox::Qspawn->new($cmd);
107                 $env->{'qspawn.filter'} = PublicInbox::GzipFilter->new;
108                 return $qsp->psgi_return($env, undef, sub {
109                         [ 200, [ qw(Content-Type application/octet-stream)]]
110                 });
111         } elsif ($path eq '/psgi-return-compressible') {
112                 require PublicInbox::Qspawn;
113                 my $cmd = [qw(echo goodbye world)];
114                 my $qsp = PublicInbox::Qspawn->new($cmd);
115                 return $qsp->psgi_return($env, undef, sub {
116                         [200, [qw(Content-Type text/plain)]]
117                 });
118         } elsif ($path eq '/psgi-return-enoent') {
119                 require PublicInbox::Qspawn;
120                 my $cmd = [ 'this-better-not-exist-in-PATH'.rand ];
121                 my $qsp = PublicInbox::Qspawn->new($cmd);
122                 return $qsp->psgi_return($env, undef, sub {
123                         [ 200, [ qw(Content-Type application/octet-stream)]]
124                 });
125         } elsif ($path eq '/pid') {
126                 $code = 200;
127                 push @$body, "$$\n";
128         } elsif ($path eq '/url_scheme') {
129                 $code = 200;
130                 push @$body, $env->{'psgi.url_scheme'}
131         } elsif ($path eq '/PI_CONFIG') {
132                 $code = 200;
133                 push @$body, $pi_config; # show value at ->refresh_groups
134         } elsif ($path =~ m!\A/exit-fifo(.+)\z!) {
135                 $code = 200;
136                 $ENV{TEST_EXIT_FIFO} = $1; # for END {}
137                 push @$body, "fifo $1 registered";
138         }
139         [ $code, $h, $body ]
140 };
141
142 builder {
143         enable 'ContentLength';
144         enable 'Head';
145         $app;
146 }