From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.2 required=3.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 7C1221F59D for ; Mon, 1 Aug 2022 21:24:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=80x24.org; s=selector1; t=1659389087; bh=gFurqN5ELmq/9d7LajCTvlCJ1BB7xp5zl3Cjh72yuhk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=mBRBS+W1r9dYWOkbaTbZ0B+h6dIljvvPX+INhP7/rqqa3CwWqjfp/olTwxdUku3sM tMamPA6wbLE6HdZTcwhCGDRQTQ6om6jaoi6SM1fqEzyoOJ0c9kss8N3+kJ1HXt9IEG bM0d9W/JHI3/bl0Ok+2m7ofdaDz1TgMRruRAVH98= From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 1/6] httpd: make internals slightly more generic Date: Mon, 1 Aug 2022 21:24:42 +0000 Message-Id: <20220801212447.270000-2-e@80x24.org> In-Reply-To: <20220801212447.270000-1-e@80x24.org> References: <20220801212447.270000-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This brings the HTTP server closer to the IMAP/NNTP/POP3 implementations and eliminates package-wide globals in PublicInbox::HTTPD. The end goal is to be able to host completely different PSGI applications on different listen ports. --- lib/PublicInbox/Daemon.pm | 10 +++---- lib/PublicInbox/HTTP.pm | 10 +++---- lib/PublicInbox/HTTPD.pm | 55 ++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/lib/PublicInbox/Daemon.pm b/lib/PublicInbox/Daemon.pm index bceae6e5..1af03cc4 100644 --- a/lib/PublicInbox/Daemon.pm +++ b/lib/PublicInbox/Daemon.pm @@ -81,11 +81,11 @@ sub load_mod ($) { my $mod = $modc.'D'; eval "require $mod"; # IMAPD|HTTPD|NNTPD|POP3D die $@ if $@; - my %xn = map { $_ => $mod->can($_) } qw(refresh post_accept); - $xn{tlsd} = $mod->new if $mod->can('refresh_groups'); #!HTTPD - my $tlsd = $xn{tlsd}; - $xn{refresh} //= sub { $tlsd->refresh_groups(@_) }; - $xn{post_accept} //= sub { $modc->new($_[0], $tlsd) }; + my %xn; + my $tlsd = $xn{tlsd} = $mod->new; + $xn{refresh} = sub { $tlsd->refresh_groups(@_) }; + $xn{post_accept} = $tlsd->can('post_accept_cb') ? + $tlsd->post_accept_cb : sub { $modc->new($_[0], $tlsd) }; $xn{af_default} = 'httpready' if $modc eq 'PublicInbox::HTTP'; \%xn; } diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm index 76e978a2..669211e3 100644 --- a/lib/PublicInbox/HTTP.pm +++ b/lib/PublicInbox/HTTP.pm @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2021 all contributors +# Copyright (C) all contributors # License: AGPL-3.0+ # # Generic PSGI server for convenience. It aims to provide @@ -52,8 +52,8 @@ sub http_date () { } sub new ($$$) { - my ($class, $sock, $addr, $httpd) = @_; - my $self = bless { httpd => $httpd }, $class; + my ($class, $sock, $addr, $srv_env) = @_; + my $self = bless { srv_env => $srv_env }, $class; my $ev = EPOLLIN; my $wbuf; if ($sock->can('accept_SSL') && !$sock->accept_SSL) { @@ -78,7 +78,7 @@ sub event_step { # called by PublicInbox::DS return read_input($self) if ref($self->{env}); my $rbuf = $self->{rbuf} // (\(my $x = '')); - my %env = %{$self->{httpd}->{env}}; # full hash copy + my %env = %{$self->{srv_env}}; # full hash copy my $r; while (($r = parse_http_request($$rbuf, \%env)) < 0) { # We do not support Trailers in chunked requests, for @@ -145,7 +145,7 @@ sub app_dispatch { # note: NOT $self->{sock}, we want our close (+ PublicInbox::DS::close), # to do proper cleanup: $env->{'psgix.io'} = $self; # for ->close or async_pass - my $res = Plack::Util::run_app($self->{httpd}->{app}, $env); + my $res = Plack::Util::run_app($env->{'pi-httpd.app'}, $env); eval { if (ref($res) eq 'CODE') { $res->(sub { response_write($self, $env, $_[0]) }); diff --git a/lib/PublicInbox/HTTPD.pm b/lib/PublicInbox/HTTPD.pm index 715e4538..bcdbb9f9 100644 --- a/lib/PublicInbox/HTTPD.pm +++ b/lib/PublicInbox/HTTPD.pm @@ -13,12 +13,17 @@ use PublicInbox::HTTPD::Async; sub pi_httpd_async { PublicInbox::HTTPD::Async->new(@_) } -sub new { - my ($class, $sock, $app, $client) = @_; - my $n = getsockname($sock) or die "not a socket: $sock $!\n"; - my ($host, $port) = PublicInbox::Daemon::host_with_port($n); +# we have a different env for ever listener socket for +# SERVER_NAME, SERVER_PORT and psgi.url_scheme +# envs: listener FD => PSGI env +sub new { bless { envs => {} }, __PACKAGE__ } - my %env = ( +# this becomes {srv_env} in PublicInbox::HTTP +sub env_for ($$$) { + my ($self, $srv, $client) = @_; + my $n = getsockname($srv) or die "not a socket: $srv $!\n"; + my ($host, $port) = PublicInbox::Daemon::host_with_port($n); + { SERVER_NAME => $host, SERVER_PORT => $port, SCRIPT_NAME => '', @@ -40,26 +45,24 @@ sub new { # this to limit git-http-backend(1) parallelism. # We also check for the truthiness of this to # detect when to use async paths for slow blobs - 'pi-httpd.async' => \&pi_httpd_async - ); - bless { app => $app, env => \%env }, $class; + 'pi-httpd.async' => \&pi_httpd_async, + 'pi-httpd.app' => $self->{app}, + } } -my %httpds; # per-listen-FD mapping for HTTPD->{env}->{SERVER_} -my $default_app; # ugh... - -sub refresh { +sub refresh_groups { + my ($self) = @_; + my $app; if (@main::ARGV) { - eval { $default_app = Plack::Util::load_psgi(@ARGV) }; - if ($@) { - die $@, -"$0 runs in /, command-line paths must be absolute\n"; - } + eval { $app = Plack::Util::load_psgi(@ARGV) }; + die $@, <new; $www->preload; - $default_app = builder { + $app = builder { eval { enable 'ReverseProxy' }; $@ and warn <call(@_) }; }; } - %httpds = (); # invalidate cache + $_->{'pi-httpd.app'} = $app for values %{$self->{envs}}; + $self->{app} = $app; } -sub post_accept { # Listener->{post_accept} - my ($client, $addr, $srv) = @_; # $_[3] - tls_wrap (unused) - my $httpd = $httpds{fileno($srv)} //= - __PACKAGE__->new($srv, $default_app, $client); - PublicInbox::HTTP->new($client, $addr, $httpd), +sub post_accept_cb { # for Listener->{post_accept} + my ($self) = @_; + sub { + my ($client, $addr, $srv) = @_; # $_[4] - tls_wrap (unused) + PublicInbox::HTTP->new($client, $addr, + $self->{envs}->{fileno($srv)} //= + env_for($self, $srv, $client)); + } } 1;