about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--lib/PublicInbox/GzipFilter.pm16
-rw-r--r--lib/PublicInbox/Qspawn.pm6
-rw-r--r--t/httpd-corner.psgi7
-rw-r--r--t/httpd-corner.t9
4 files changed, 35 insertions, 3 deletions
diff --git a/lib/PublicInbox/GzipFilter.pm b/lib/PublicInbox/GzipFilter.pm
index 0fbb4476..0a6c56a5 100644
--- a/lib/PublicInbox/GzipFilter.pm
+++ b/lib/PublicInbox/GzipFilter.pm
@@ -32,6 +32,22 @@ sub gzf_maybe ($$) {
         bless { gz => $gz }, __PACKAGE__;
 }
 
+sub qsp_maybe ($$) {
+        my ($res_hdr, $env) = @_;
+        return if ($env->{HTTP_ACCEPT_ENCODING} // '') !~ /\bgzip\b/;
+        my $hdr = join("\n", @$res_hdr);
+        return if $hdr !~ m!^Content-Type\n
+                                (?:(?:text/(?:html|plain))|
+                                application/atom\+xml)\b!ixsm;
+        return if $hdr =~ m!^Content-Encoding\ngzip\n!smi;
+        return if $hdr =~ m!^Content-Length\n[0-9]+\n!smi;
+        return if $hdr =~ m!^Transfer-Encoding\n!smi;
+        # in case Plack::Middleware::Deflater is loaded:
+        return if $env->{'plack.skip-deflater'}++;
+        push @$res_hdr, @GZIP_HDRS;
+        bless {}, __PACKAGE__;
+}
+
 sub gzip_or_die () {
         my ($gz, $err) = Compress::Raw::Zlib::Deflate->new(%OPT);
         $err == Z_OK or die "Deflate->new failed: $err";
diff --git a/lib/PublicInbox/Qspawn.pm b/lib/PublicInbox/Qspawn.pm
index d395a10b..88b6d390 100644
--- a/lib/PublicInbox/Qspawn.pm
+++ b/lib/PublicInbox/Qspawn.pm
@@ -25,8 +25,8 @@
 
 package PublicInbox::Qspawn;
 use strict;
-use warnings;
 use PublicInbox::Spawn qw(popen_rd);
+use PublicInbox::GzipFilter;
 
 # n.b.: we get EAGAIN with public-inbox-httpd, and EINTR on other PSGI servers
 use Errno qw(EAGAIN EINTR);
@@ -255,7 +255,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
diff --git a/t/httpd-corner.psgi b/t/httpd-corner.psgi
index 44629620..cb41cfa0 100644
--- a/t/httpd-corner.psgi
+++ b/t/httpd-corner.psgi
@@ -94,6 +94,13 @@ my $app = sub {
                 return $qsp->psgi_return($env, undef, sub {
                         [ 200, [ qw(Content-Type application/octet-stream)]]
                 });
+        } elsif ($path eq '/psgi-return-compressible') {
+                require PublicInbox::Qspawn;
+                my $cmd = [qw(echo goodbye world)];
+                my $qsp = PublicInbox::Qspawn->new($cmd);
+                return $qsp->psgi_return($env, undef, sub {
+                        [200, [qw(Content-Type text/plain)]]
+                });
         } elsif ($path eq '/psgi-return-enoent') {
                 require PublicInbox::Qspawn;
                 my $cmd = [ 'this-better-not-exist-in-PATH'.rand ];
diff --git a/t/httpd-corner.t b/t/httpd-corner.t
index 68148655..514672a1 100644
--- a/t/httpd-corner.t
+++ b/t/httpd-corner.t
@@ -340,11 +340,18 @@ SKIP: {
         is($n, 30 * 1024 * 1024, 'got expected output from curl');
         is($non_zero, 0, 'read all zeros');
 
-        require_mods(@zmods, 2);
+        require_mods(@zmods, 4);
         my $buf = xqx([$curl, '-sS', "$base/psgi-return-gzip"]);
         is($?, 0, 'curl succesful');
         IO::Uncompress::Gunzip::gunzip(\$buf => \(my $out));
         is($out, "hello world\n");
+        my $curl_rdr = { 2 => \(my $curl_err = '') };
+        $buf = xqx([$curl, qw(-sSv --compressed),
+                        "$base/psgi-return-compressible"], undef, $curl_rdr);
+        is($?, 0, 'curl --compressed successful');
+        is($buf, "goodbye world\n", 'gzipped response as expected');
+        like($curl_err, qr/\bContent-Encoding: gzip\b/,
+                'curl got gzipped response');
 }
 
 {