X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FQspawn.pm;h=68b7111278f52626462a36f5263ccf4096c25b6d;hb=af0b0fb7a454470a32c452119d0392e0dedb3fe1;hp=34b6912fea558dd01ee924f463e180f946fd26e1;hpb=d111c17ff06c9af7e0690e4b00a0eeb1c505c92a;p=public-inbox.git
diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm
index 34b6912f..68b71112 100644
--- a/lib/PublicInbox/Qspawn.pm
+++ b/lib/PublicInbox/Qspawn.pm
@@ -1,4 +1,4 @@
-# Copyright (C) 2016-2020 all contributors
+# Copyright (C) 2016-2021 all contributors
# License: AGPL-3.0+
# Like most Perl modules in public-inbox, this is internal and
@@ -12,12 +12,13 @@
# operate in. This can be useful to ensure smaller inboxes can
# be cloned while cloning of large inboxes is maxed out.
#
-# This does not depend on PublicInbox::DS or any other external
-# scheduling mechanism, you just need to call start() and finish()
-# appropriately. However, public-inbox-httpd (which uses PublicInbox::DS)
-# will be able to schedule this based on readability of stdout from
-# the spawned process. See GitHTTPBackend.pm and SolverGit.pm for
-# usage examples. It does not depend on any form of threading.
+# This does not depend on the PublicInbox::DS->EventLoop or any
+# other external scheduling mechanism, you just need to call
+# start() and finish() appropriately. However, public-inbox-httpd
+# (which uses PublicInbox::DS) will be able to schedule this
+# based on readability of stdout from the spawned process.
+# See GitHTTPBackend.pm and SolverGit.pm for usage examples.
+# It does not depend on any form of threading.
#
# This is useful for scheduling CGI execution of both long-lived
# git-http-backend(1) process (for "git clone") as well as short-lived
@@ -25,8 +26,9 @@
package PublicInbox::Qspawn;
use strict;
-use warnings;
use PublicInbox::Spawn qw(popen_rd);
+use PublicInbox::GzipFilter;
+use PublicInbox::DS qw(dwaitpid); # doesn't need event loop
# n.b.: we get EAGAIN with public-inbox-httpd, and EINTR on other PSGI servers
use Errno qw(EAGAIN EINTR);
@@ -48,7 +50,7 @@ sub _do_spawn {
my ($cmd, $cmd_env, $opt) = @{delete $self->{args}};
my %o = %{$opt || {}};
$self->{limiter} = $limiter;
- foreach my $k (PublicInbox::Spawn::RLIMITS()) {
+ foreach my $k (@PublicInbox::Spawn::RLIMITS) {
if (defined(my $rlimit = $limiter->{$k})) {
$o{$k} = $rlimit;
}
@@ -116,37 +118,12 @@ sub finalize ($$) {
}
# callback for dwaitpid
-sub waitpid_err ($$) {
- my ($self, $pid) = @_;
- my $xpid = delete $self->{pid};
- my $err;
- if (defined $pid) {
- if ($pid > 0) { # success!
- $err = child_err($?);
- } elsif ($pid < 0) { # ??? does this happen in our case?
- $err = "W: waitpid($xpid, 0) => $pid: $!";
- } # else should not be called with pid == 0
- }
- finalize($self, $err);
-}
-
-sub do_waitpid ($) {
- my ($self) = @_;
- my $pid = $self->{pid};
- # PublicInbox::DS may not be loaded
- eval { PublicInbox::DS::dwaitpid($pid, \&waitpid_err, $self) };
- # done if we're running in PublicInbox::DS::EventLoop
- if ($@) {
- # non public-inbox-{httpd,nntpd} callers may block:
- my $ret = waitpid($pid, 0);
- waitpid_err($self, $ret);
- }
-}
+sub waitpid_err { finalize($_[0], child_err($?)) }
sub finish ($;$) {
my ($self, $err) = @_;
if (delete $self->{rpipe}) {
- do_waitpid($self);
+ dwaitpid $self->{pid}, \&waitpid_err, $self;
} else {
finalize($self, $err);
}
@@ -234,7 +211,11 @@ sub rd_hdr ($) {
length($$hdr_buf));
if (defined($r)) {
$total_rd += $r;
- $ret = $ph_cb->($total_rd, $hdr_buf, $ph_arg);
+ eval { $ret = $ph_cb->($total_rd, $hdr_buf, $ph_arg) };
+ if ($@) {
+ log_err($self->{psgi_env}, "parse_hdr: $@");
+ $ret = [ 500, [], [ "Internal error\n" ] ];
+ }
} else {
# caller should notify us when it's ready:
return if $! == EAGAIN;
@@ -251,7 +232,9 @@ sub psgi_return_init_cb {
my ($self) = @_;
my $r = rd_hdr($self) or return;
my $env = $self->{psgi_env};
- my $filter = delete $env->{'qspawn.filter'};
+ my $filter = delete $env->{'qspawn.filter'} //
+ PublicInbox::GzipFilter::qsp_maybe($r->[1], $env);
+
my $wcb = delete $env->{'qspawn.wcb'};
my $async = delete $self->{async};
if (scalar(@$r) == 3) { # error
@@ -277,10 +260,6 @@ sub psgi_return_init_cb {
${$self->{hdr_buf}}, $filter);
$wcb->($r);
}
-
- # Workaround a leak under Perl 5.16.3 when combined with
- # Plack::Middleware::Deflater:
- $wcb = undef;
}
sub psgi_return_start { # may run later, much later...
@@ -357,12 +336,12 @@ sub new {
}
sub setup_rlimit {
- my ($self, $name, $config) = @_;
- foreach my $rlim (PublicInbox::Spawn::RLIMITS()) {
+ my ($self, $name, $cfg) = @_;
+ foreach my $rlim (@PublicInbox::Spawn::RLIMITS) {
my $k = lc($rlim);
$k =~ tr/_//d;
$k = "publicinboxlimiter.$name.$k";
- defined(my $v = $config->{$k}) or next;
+ defined(my $v = $cfg->{$k}) or next;
my @rlimit = split(/\s*,\s*/, $v);
if (scalar(@rlimit) == 1) {
push @rlimit, $rlimit[0];