FU::Util: Add gzip_compress() wrapper for libdeflate/zlib-ng/zlib

And use it for automatic output compression in FU, as (potentially)
faster alternative to Compress::Raw::Zlib.

Was also planning to maybe add support for Zstd or Brotli, but given the
performance of libdeflate, I'm not sure that's really necessary. Brotli
does tend to do a better job at compressing HTML, though.
This commit is contained in:
Yorhel 2025-03-18 16:58:31 +01:00
parent c2e0f158ac
commit bc33fe53f0
5 changed files with 237 additions and 10 deletions

14
FU.pm
View file

@ -850,7 +850,6 @@ sub _error_page($, $code, $title, $msg) {
}
sub _finalize {
state $haszlib = eval { require Compress::Raw::Zlib; 1 };
my $r = $FU::REQ;
fu->add_header('set-cookie', $_) for $r->{rescookie} ? sort values $r->{rescookie}->%* : ();
@ -862,18 +861,14 @@ sub _finalize {
$r->{resbody} = '';
} else {
if ($haszlib && length($r->{resbody}) > 256
if (FU::Util::gzip_lib() && length($r->{resbody}) > 256
&& !defined $r->{reshdr}{'content-encoding'} && FU::compress_mimes->{$r->{reshdr}{'content-type'}}) {
$r->{reshdr}{'vary'} = ($r->{reshdr}{'vary'} ? $r->{reshdr}{'vary'}.', ' : '').'accept-encoding'
if ($r->{reshdr}{'vary'}||'') !~ /accept-encoding/i;
if ($haszlib && ($r->{hdr}{'accept-encoding'}||'') =~ /gzip/) {
# Use lower-level API because the higher-level Compress::Zlib loads a whole bunch of other modules.
my $z = Compress::Raw::Zlib::Deflate->new(-WindowBits => Compress::Raw::Zlib::WANT_GZIP(), -Level => 3, -AppendOutput => 1);
$z->deflate($r->{resbody}, my $buf);
$z->flush($buf);
$r->{resbody} = $buf;
if (($r->{hdr}{'accept-encoding'}||'') =~ /gzip/) {
$r->{resbody} = FU::Util::gzip_compress(6, $r->{resbody});
$r->{reshdr}{'content-encoding'} = 'gzip';
}
}
@ -993,6 +988,9 @@ is). There are a few additional optional dependencies:
=item * C<libpq.so> - required for L<FU::Pg>, dynamically loaded through
C<dlopen()>.
=item * C<libdeflate.so> or C<libz-ng.so> or C<libz.so> - required for
C<gzip_compress()> in L<FU::Util> and used for HTTP output compression.
=back