diff options
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | lib/PublicInbox/GzipFilter.pm | 28 | ||||
-rw-r--r-- | lib/PublicInbox/NoopFilter.pm | 13 | ||||
-rw-r--r-- | lib/PublicInbox/WwwListing.pm | 25 | ||||
-rw-r--r-- | t/www_listing.t | 8 |
5 files changed, 62 insertions, 13 deletions
@@ -159,6 +159,7 @@ lib/PublicInbox/NNTP.pm lib/PublicInbox/NNTPD.pm lib/PublicInbox/NNTPdeflate.pm lib/PublicInbox/NewsWWW.pm +lib/PublicInbox/NoopFilter.pm lib/PublicInbox/Over.pm lib/PublicInbox/OverIdx.pm lib/PublicInbox/ParentPipe.pm diff --git a/lib/PublicInbox/GzipFilter.pm b/lib/PublicInbox/GzipFilter.pm index 95fced05..8cc5ea00 100644 --- a/lib/PublicInbox/GzipFilter.pm +++ b/lib/PublicInbox/GzipFilter.pm @@ -42,7 +42,7 @@ sub gzf_maybe ($$) { # for GetlineBody (via Qspawn) when NOT using $env->{'pi-httpd.async'} # Also used for ->getline callbacks sub translate ($$) { - my $self = $_[0]; + my $self = $_[0]; # $_[1] => input # allocate the zlib context lazily here, instead of in ->new. # Deflate contexts are memory-intensive and this object may @@ -72,10 +72,34 @@ sub write { $_[0]->{fh}->write(translate($_[0], $_[1])); } +# similar to ->translate; use this when we're sure we know we have +# more data to buffer after this +sub zmore { + my $self = $_[0]; # $_[1] => input + my $err = $self->{gz}->deflate($_[1], $self->{zbuf}); + die "gzip->deflate: $err" if $err != Z_OK; + ''; +} + +# flushes and returns the final bit of gzipped data +sub zflush ($;$) { + my $self = $_[0]; # $_[1] => final input (optional) + my $zbuf = delete $self->{zbuf}; + my $gz = delete $self->{gz}; + my $err; + if (defined $_[1]) { + $err = $gz->deflate($_[1], $zbuf); + die "gzip->deflate: $err" if $err != Z_OK; + } + $err = $gz->flush($zbuf, Z_FINISH); + die "gzip->flush: $err" if $err != Z_OK; + $zbuf; +} + sub close { my ($self) = @_; my $fh = delete $self->{fh}; - $fh->write(translate($self, undef)); + $fh->write(zflush($self)); $fh->close; } diff --git a/lib/PublicInbox/NoopFilter.pm b/lib/PublicInbox/NoopFilter.pm new file mode 100644 index 00000000..b9c00ff7 --- /dev/null +++ b/lib/PublicInbox/NoopFilter.pm @@ -0,0 +1,13 @@ +# Copyright (C) 2020 all contributors <meta@public-inbox.org> +# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt> + +package PublicInbox::NoopFilter; +use strict; + +sub new { bless \(my $ignore), __PACKAGE__ } + +# noop workalike for PublicInbox::GzipFilter methods +sub translate { $_[1] // '' } +sub zmore { $_[1] } +sub zflush { $_[1] // '' } +1; diff --git a/lib/PublicInbox/WwwListing.pm b/lib/PublicInbox/WwwListing.pm index a3d4e2b3..780c97e9 100644 --- a/lib/PublicInbox/WwwListing.pm +++ b/lib/PublicInbox/WwwListing.pm @@ -10,6 +10,8 @@ use PublicInbox::Hval qw(ascii_html prurl); use PublicInbox::Linkify; use PublicInbox::View; use PublicInbox::Inbox; +use PublicInbox::NoopFilter; +use PublicInbox::GzipFilter qw(gzf_maybe); use bytes (); # bytes::length use HTTP::Date qw(time2str); use Digest::SHA (); @@ -104,13 +106,15 @@ sub ibx_entry { sub html ($$) { my ($env, $list) = @_; - my $title = 'public-inbox'; - my $out = ''; + my $h = [ 'Content-Type', 'text/html; charset=UTF-8', + 'Content-Length', undef ]; + my $gzf = gzf_maybe($h, $env) || PublicInbox::NoopFilter::new(); + my $out = $gzf->zmore('<html><head><title>' . + 'public-inbox listing</title>' . + '</head><body><pre>'); my $code = 404; if (@$list) { - $title .= ' - listing'; $code = 200; - # Schwartzian transform since Inbox->modified is expensive @$list = sort { $b->[0] <=> $a->[0] @@ -118,13 +122,14 @@ sub html ($$) { my $tmp = join("\n", map { ibx_entry(@$_, $env) } @$list); my $l = PublicInbox::Linkify->new; - $out = '<pre>'.$l->to_html($tmp).'</pre><hr>'; + $out .= $gzf->zmore($l->to_html($tmp)); + } else { + $out .= $gzf->zmore('no inboxes, yet'); } - $out = "<html><head><title>$title</title></head><body>" . $out; - $out .= '<pre>'. PublicInbox::WwwStream::code_footer($env) . - '</pre></body></html>'; - - my $h = [ 'Content-Type', 'text/html; charset=UTF-8' ]; + $out .= $gzf->zflush('</pre><hr><pre>'. + PublicInbox::WwwStream::code_footer($env) . + '</pre></body></html>'); + $h->[3] = bytes::length($out); [ $code, $h, [ $out ] ]; } diff --git a/t/www_listing.t b/t/www_listing.t index 0aededd4..c4511cd1 100644 --- a/t/www_listing.t +++ b/t/www_listing.t @@ -35,13 +35,19 @@ like(PublicInbox::WwwListing::fingerprint($bare), qr/\A[a-f0-9]{40}\z/, sub tiny_test { my ($json, $host, $port) = @_; + my $tmp; my $http = HTTP::Tiny->new; my $res = $http->get("http://$host:$port/"); is($res->{status}, 200, 'got HTML listing'); like($res->{content}, qr!</html>!si, 'listing looks like HTML'); + + $res = $http->get("http://$host:$port/", {'Accept-Encoding'=>'gzip'}); + is($res->{status}, 200, 'got gzipped HTML listing'); + IO::Uncompress::Gunzip::gunzip(\(delete $res->{content}) => \$tmp); + like($tmp, qr!</html>!si, 'unzipped listing looks like HTML'); + $res = $http->get("http://$host:$port/manifest.js.gz"); is($res->{status}, 200, 'got manifest'); - my $tmp; IO::Uncompress::Gunzip::gunzip(\(delete $res->{content}) => \$tmp); unlike($tmp, qr/"modified":\s*"/, 'modified is an integer'); my $manifest = $json->decode($tmp); |