chiark / gitweb /
changelog: start 9.14
[dgit.git] / tests / http-static-server
1 #!/usr/bin/perl -w
2 #
3 # This file is part of the dgit test suite.
4 #
5 # Copyright (C)2004-2015 Best Practical Solutions, LLC
6 # Copyright (C)2019      Ian Jackson
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 #
19 # invocation protocol:
20 #
21 #   http-static-server >port-file tests/tmp/$thing/aq
22 #
23 # Will write the allocated port number to port-file.
24 # Then we fork and the parent exits 0.
25 # If port-file is unlinked, we exit.
26
27 use strict;
28 use IO::Handle;
29
30 our ($webroot) = @ARGV;
31 our $port = '';
32
33 # HTTP::Server::Simple handles requests in the main process so it
34 # must redirect and close STDOUT.  So transplant STDOUT to CHECK.
35 open CHECK, ">& STDOUT" or die $!;
36 open STDOUT, ">/dev/null" or die $!;
37
38 sub stat_type_check () {
39     die "[$port, $webroot] stdout not ta plain file"
40         unless -f _;
41 }
42
43 stat CHECK or die $!;
44 stat_type_check();
45
46 sub start_polling_fstat () {
47     our $polling_pid = $$;
48     $SIG{ALRM} = sub {
49         return unless $$ = $polling_pid;
50         stat CHECK or die $!;
51         my $nlink = (stat _)[3];
52         exit 0 unless $nlink;
53         stat_type_check(); # doesn't seem possible to fail but check anyway
54         alarm(1);
55     };
56     alarm(1);
57 }
58
59 package ServerClass;
60
61 use strict;
62 use Socket qw(AF_INET SOCK_STREAM);
63 use Socket qw(AF_INET SOCK_STREAM unpack_sockaddr_in);
64 use IO::Handle;
65
66 use base qw(HTTP::Server::Simple::CGI);
67 use HTTP::Server::Simple::Static;
68
69 sub handle_request {
70     my ($self, $cgi) = @_;
71
72     if (!$self->serve_static($cgi, $::webroot)) {
73         print "HTTP/1.0 404 Not found\r\n";
74         print $cgi->header,
75             $cgi->start_html('Not found'),
76             $cgi->h1('Not found'),
77             $cgi->end_html;
78     }
79 }
80
81 sub port () { return 0; }
82
83 sub after_setup_listener () {
84     my $sn = getsockname HTTP::Server::Simple::HTTPDaemon or die $!;
85     ($main::port,) = unpack_sockaddr_in $sn;
86     print main::CHECK $port, "\n" or die $!;
87     flush main::CHECK or die $!;
88     my $c = fork // die $!;
89     exit 0 if $c;
90     ::main::start_polling_fstat();
91 }
92
93 package main;
94
95 our $server = ServerClass->new();
96 $server->run();