about summary refs log tree commit homepage
path: root/script/public-inbox-httpd
blob: 215796225d8043c95e7e8ce219289c45cc86d762 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/perl -w
# Copyright (C) 2016 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
#
# Standalone HTTP server for public-inbox.
use strict;
use warnings;
use Plack::Util;
use PublicInbox::Daemon;
use PublicInbox::HTTP;
use Plack::Request;
use Plack::Builder;
my %httpds;
my $app;
my $refresh = sub {
	if (@ARGV) {
		eval { $app = Plack::Util::load_psgi(@ARGV) };
		if ($@) {
			die $@,
"$0 runs in /, command-line paths must be absolute\n";
		}
	} else {
		require PublicInbox::WWW;
		PublicInbox::WWW->preload;
		my $www = PublicInbox::WWW->new;
		$app = eval {
			builder {
				enable 'Chunked';
				eval {
					enable 'Deflater',
						content_type => [ qw(
							text/html
							text/plain
							application/atom+xml
							)]
				};
				$@ and warn
"Plack::Middleware::Deflater missing, bandwidth will be wasted\n";

				eval { enable 'ReverseProxy' };
				$@ and warn
"Plack::Middleware::ReverseProxy missing,\n",
"URL generation for redirects may be wrong if behind a reverse proxy\n";

				enable 'Head';
				sub { $www->call(@_) };
			};
		};
	}
};

daemon_run('0.0.0.0:8080', $refresh,
	sub ($$$) { # post_accept
		my ($client, $addr, $srv) = @_;
		my $fd = fileno($srv);
		my $h = $httpds{$fd} ||= PublicInbox::HTTPD->new($srv, $app);
		PublicInbox::HTTP->new($client, $addr, $h),
	});

1;

# XXX This is a totally unstable API for public-inbox internal use only
# This is exposed via the 'pi-httpd.async' key in the PSGI env hash.
# The name of this key is not even stable!
# Currently is is intended for use with read-only pipes.
package PublicInbox::HTTPD::Async;
use strict;
use warnings;
use base qw(Danga::Socket);
use fields qw(cb);

sub new {
	my ($class, $io, $cb) = @_;
	my $self = fields::new($class);
	IO::Handle::blocking($io, 0);
	$self->SUPER::new($io);
	$self->{cb} = $cb;
	$self->watch_read(1);
	$self;
}

sub event_read { $_[0]->{cb}->() }
sub event_hup { $_[0]->{cb}->() }
sub event_err { $_[0]->{cb}->() }
sub sysread { shift->{sock}->sysread(@_) }

1;

package PublicInbox::HTTPD;
use strict;
use warnings;
use Plack::Util;

sub pi_httpd_async {
	my ($io, $cb) = @_;
	PublicInbox::HTTPD::Async->new($io, $cb);
}

sub new {
	my ($class, $sock, $app) = @_;
	my $n = getsockname($sock) or die "not a socket: $sock $!\n";
	my ($port, $addr);
	if (length($n) >= 28) {
		require Socket6;
		($port, $addr) = Socket6::unpack_sockaddr_in6($n);
	} else {
		($port, $addr) = Socket::unpack_sockaddr_in($n);
	}

	my %env = (
		REMOTE_HOST => '',
		REMOTE_PORT => 0,
		SERVER_NAME => $addr,
		SERVER_PORT => $port,
		SCRIPT_NAME => '',
		'psgi.version' => [ 1, 1 ],
		'psgi.errors' => \*STDERR,
		'psgi.url_scheme' => 'http',
		'psgi.nonblocking' => Plack::Util::TRUE,
		'psgi.streaming' => Plack::Util::TRUE,
		'psgi.run_once'	 => Plack::Util::FALSE,
		'psgi.multithread' => Plack::Util::FALSE,
		'psgi.multiprocess' => Plack::Util::TRUE,
		'psgix.harakiri'=> Plack::Util::FALSE,
		'psgix.input.buffered' => Plack::Util::TRUE,
		'pi-httpd.async' => do {
			no warnings 'once';
			*pi_httpd_async
		},
	);
	bless {
		app => $app,
		env => \%env,
	}, $class;
}

1;