Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package perl-Furl for openSUSE:Factory checked in at 2026-11-10 16:30:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Furl (Old) and /work/SRC/openSUSE:Factory/.perl-Furl.new.3759290 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Furl" Tue Nov 10 16:30:04 2026 rev:5 rq:1396532 version:3.160.0 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Furl/perl-Furl.changes 2025-10-22 12:18:33.421214844 +0200 +++ /work/SRC/openSUSE:Factory/.perl-Furl.new.3759290/perl-Furl.changes 2026-11-10 16:30:22.247668414 +0100 @@ -1,0 +2,16 @@ +Tue Nov 10 13:31:22 UTC 2026 - Tina Müller <[email protected]> + +- updated to 3.160.0 (3.16) + see /usr/share/doc/packages/perl-Furl/Changes + + 3.16 2026-11-06T10:22:58Z + - [SECURITY] Fix memory exhaustion via unbounded decompression of gzip/deflate + responses, a.k.a. "zip bomb" (CVE-2026-65059) (#139, robrwo++) + bsc#1289200 + - Add max_decompressed_size option to limit the size of a decoded response body. + By default the limit is 100 MiB for responses held in memory, and there is no + limit for responses streamed with write_file/write_code. Going over the + limit makes the request return an internal 500 response (with + X-Internal-Response) (#140) + +------------------------------------------------------------------- Old: ---- Furl-3.15.tar.gz New: ---- Furl-3.16.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Furl.spec ++++++ --- /var/tmp/diff_new_pack.zDGvg5/_old 2026-11-10 16:30:23.816734045 +0100 +++ /var/tmp/diff_new_pack.zDGvg5/_new 2026-11-10 16:30:23.818734128 +0100 @@ -1,7 +1,7 @@ # # spec file for package perl-Furl # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,14 +18,14 @@ %define cpan_name Furl Name: perl-Furl -Version: 3.150.0 +Version: 3.160.0 Release: 0 -# 3.15 -> normalize -> 3.150.0 -%define cpan_version 3.15 +# 3.16 -> normalize -> 3.160.0 +%define cpan_version 3.16 License: Artistic-1.0 OR GPL-1.0-or-later Summary: Lightning-fast URL fetcher URL: https://metacpan.org/release/%{cpan_name} -Source0: https://cpan.metacpan.org/authors/id/S/SY/SYOHEX/%{cpan_name}-%{cpan_version}.tar.gz +Source0: https://cpan.metacpan.org/authors/id/T/TO/TOKUHIROM/%{cpan_name}-%{cpan_version}.tar.gz Source1: cpanspec.yml Source100: README.md Patch0: 0001-Remove-use-of-Mozilla-CA.patch ++++++ Furl-3.15.tar.gz -> Furl-3.16.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/Changes new/Furl-3.16/Changes --- old/Furl-3.15/Changes 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/Changes 2026-11-06 11:22:58.000000000 +0100 @@ -1,5 +1,14 @@ Revision history for Perl module Furl +3.16 2026-11-06T10:22:58Z + - [SECURITY] Fix memory exhaustion via unbounded decompression of gzip/deflate + responses, a.k.a. "zip bomb" (CVE-2026-65059) (#139, robrwo++) + - Add max_decompressed_size option to limit the size of a decoded response body. + By default the limit is 100 MiB for responses held in memory, and there is no + limit for responses streamed with write_file/write_code. Going over the + limit makes the request return an internal 500 response (with + X-Internal-Response) (#140) + 3.15 2025-09-25T00:24:03Z - Fix the issue that when timeout happens, then request method returns success when there is no Content-Length headers(#137) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/MANIFEST new/Furl-3.16/MANIFEST --- old/Furl-3.15/MANIFEST 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/MANIFEST 2026-11-06 11:22:58.000000000 +0100 @@ -64,6 +64,7 @@ t/300_high/05_suppress_dup_host_header.t t/300_high/06_keep_request.t t/300_high/07_cookie.t +t/300_high/41_max_decompressed_size.t t/300_high/99_error.t t/400_components/001_response-coding/01-file.t t/400_components/001_response-coding/t-euc-jp.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/META.json new/Furl-3.16/META.json --- old/Furl-3.15/META.json 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/META.json 2026-11-06 11:22:58.000000000 +0100 @@ -4,7 +4,7 @@ "Tokuhiro Matsuno <[email protected]>" ], "dynamic_config" : 0, - "generated_by" : "Minilla/v3.1.28", + "generated_by" : "Minilla/v3.3.2", "license" : [ "perl_5" ], @@ -110,14 +110,14 @@ "provides" : { "Furl" : { "file" : "lib/Furl.pm", - "version" : "3.15" + "version" : "3.16" }, "Furl::ConnectionCache" : { "file" : "lib/Furl/ConnectionCache.pm" }, "Furl::HTTP" : { "file" : "lib/Furl/HTTP.pm", - "version" : "3.15" + "version" : "3.16" }, "Furl::Headers" : { "file" : "lib/Furl/Headers.pm" @@ -144,11 +144,13 @@ "web" : "https://github.com/tokuhirom/Furl" } }, - "version" : "3.15", + "version" : "3.16", "x_contributors" : [ "Audrey Tang <[email protected]>", "Breno G. de Oliveira <[email protected]>", + "Claude <[email protected]>", "Debabrata Deka <[email protected]>", + "Ed Sabol <[email protected]>", "Fuji Goro <[email protected]>", "Fuji, Goro <[email protected]>", "Fuji, Goro <[email protected]>", @@ -160,6 +162,7 @@ "Keiji, Yoshimi <[email protected]>", "Masahiro Nagano <[email protected]>", "Neil Bowers <[email protected]>", + "Robert Rothenberg <[email protected]>", "Shohei YOSHIDA <[email protected]>", "Shoichi Kaji <[email protected]>", "Slaven Rezic <[email protected]>", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/META.yml new/Furl-3.16/META.yml --- old/Furl-3.15/META.yml 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/META.yml 2026-11-06 11:22:58.000000000 +0100 @@ -10,7 +10,7 @@ configure_requires: Module::Build::Tiny: '0.035' dynamic_config: 0 -generated_by: 'Minilla/v3.1.28, CPAN::Meta::Converter version 2.150010' +generated_by: 'Minilla/v3.3.2, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -29,12 +29,12 @@ provides: Furl: file: lib/Furl.pm - version: '3.15' + version: '3.16' Furl::ConnectionCache: file: lib/Furl/ConnectionCache.pm Furl::HTTP: file: lib/Furl/HTTP.pm - version: '3.15' + version: '3.16' Furl::Headers: file: lib/Furl/Headers.pm Furl::Request: @@ -62,11 +62,13 @@ bugtracker: https://github.com/tokuhirom/Furl/issues homepage: https://github.com/tokuhirom/Furl repository: https://github.com/tokuhirom/Furl.git -version: '3.15' +version: '3.16' x_contributors: - 'Audrey Tang <[email protected]>' - 'Breno G. de Oliveira <[email protected]>' + - 'Claude <[email protected]>' - 'Debabrata Deka <[email protected]>' + - 'Ed Sabol <[email protected]>' - 'Fuji Goro <[email protected]>' - 'Fuji, Goro <[email protected]>' - 'Fuji, Goro <[email protected]>' @@ -78,6 +80,7 @@ - 'Keiji, Yoshimi <[email protected]>' - 'Masahiro Nagano <[email protected]>' - 'Neil Bowers <[email protected]>' + - 'Robert Rothenberg <[email protected]>' - 'Shohei YOSHIDA <[email protected]>' - 'Shoichi Kaji <[email protected]>' - 'Slaven Rezic <[email protected]>' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/README.md new/Furl-3.16/README.md --- old/Furl-3.15/README.md 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/README.md 2026-11-06 11:22:58.000000000 +0100 @@ -46,6 +46,10 @@ - agent :Str = "Furl/$VERSION" - timeout :Int = 10 - max\_redirects :Int = 7 +- max\_decompressed\_size :Int + + Maximum size of a gzip/deflate-decoded response body; `0` disables the limit. Defaults to 100 MiB for responses held in memory, and to no limit for responses streamed with `write_file` or `write_code`. See ["new" in Furl::HTTP](https://metacpan.org/pod/Furl%3A%3AHTTP#new). + - capture\_request :Bool = false If this parameter is true, [Furl::HTTP](https://metacpan.org/pod/Furl%3A%3AHTTP) captures raw request string. @@ -159,7 +163,7 @@ # FAQ -- Does Furl depends on XS modules? +- Does Furl depend on XS modules? No. Although some optional features require XS modules, basic features are available without XS modules. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/lib/Furl/HTTP.pm new/Furl-3.16/lib/Furl/HTTP.pm --- old/Furl-3.15/lib/Furl/HTTP.pm 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/lib/Furl/HTTP.pm 2026-11-06 11:22:58.000000000 +0100 @@ -4,7 +4,7 @@ use base qw/Exporter/; use 5.008001; -our $VERSION = '3.15'; +our $VERSION = '3.16'; use Carp (); use Furl::ConnectionCache; @@ -36,6 +36,9 @@ my $HTTP_TOKEN = '[^\x00-\x31\x7F]+'; my $HTTP_QUOTED_STRING = q{"([^"]+|\\.)*"}; +# Default for max_decompressed_size when the body is held in memory. +our $DEFAULT_MAX_DECOMPRESSED_SIZE = 100 * 1024 * 1024; + sub new { my $class = shift; my %args = @_ == 1 ? %{$_[0]} : @_; @@ -534,7 +537,16 @@ if (exists $COMPRESSED{ $special_headers->{'content-encoding'} }) { _requires('Furl/ZlibStream.pm', 'Content-Encoding', 'Compress::Raw::Zlib'); - $res_content = Furl::ZlibStream->new($res_content); + # An explicit limit (per request, or given to new) always applies. + # Otherwise the default limit applies only when the body is held in + # memory; a body streamed with write_file/write_code does not grow + # in memory, so it is left unlimited as before. + my $max_decompressed_size + = defined($args{max_decompressed_size}) ? $args{max_decompressed_size} + : defined($self->{max_decompressed_size}) ? $self->{max_decompressed_size} + : ref($res_content) ? 0 + : $DEFAULT_MAX_DECOMPRESSED_SIZE; + $res_content = Furl::ZlibStream->new($res_content, $max_decompressed_size); } my $chunked = ($special_headers->{'transfer-encoding'} eq 'chunked'); @@ -548,20 +560,31 @@ || $res_status == 204 || $res_status == 304) { my @err; - if ( $chunked ) { - @err = $self->_read_body_chunked($sock, - \$res_content, $rest_header, $timeout_at); - } else { - $res_content .= $rest_header; - if (ref $res_content || !defined($content_length)) { - @err = $self->_read_body_normal($sock, - \$res_content, length($rest_header), - $content_length, $timeout_at); + my $ok = eval { + if ( $chunked ) { + @err = $self->_read_body_chunked($sock, + \$res_content, $rest_header, $timeout_at); } else { - @err = $self->_read_body_normal_to_string_buffer($sock, - \$res_content, length($rest_header), - $content_length, $timeout_at); + $res_content .= $rest_header; + if (ref $res_content || !defined($content_length)) { + @err = $self->_read_body_normal($sock, + \$res_content, length($rest_header), + $content_length, $timeout_at); + } else { + @err = $self->_read_body_normal_to_string_buffer($sock, + \$res_content, length($rest_header), + $content_length, $timeout_at); + } } + 1; + }; + unless ($ok) { + my $e = $@; + # The rest of the body is left unread, so the connection is + # dropped rather than returned to the pool. + return $self->_r500("$e") + if ref($e) && ref($e) eq 'Furl::ZlibStream::LimitExceeded'; + die $e; } if(@err) { return @err; @@ -1060,7 +1083,7 @@ 1; __END__ -=for stopwords sockaddr +=for stopwords sockaddr MiB =encoding utf8 @@ -1121,6 +1144,12 @@ =item max_redirects :Int = 7 +=item max_decompressed_size :Int + +Maximum size, in bytes, of a response body after B<Content-Encoding> (gzip, deflate) decoding, so that a small response from a malicious or compromised server cannot expand without bound in memory (a "decompression bomb"). When a body inflates past this limit, reading stops, the connection is closed and C<< $furl->request >> returns an internal C<500> response (with the C<X-Internal-Response> header) whose message mentions C<max_decompressed_size>. Set it to C<0> to disable the limit. + +If you do not set it, a limit of 104857600 bytes (100 MiB) applies to responses held in memory, and no limit applies to responses streamed with C<write_file> or C<write_code>, as their bodies do not grow in memory. If you set it, the limit applies to both. + =item proxy :Str =item no_proxy :Str @@ -1233,6 +1262,10 @@ It's like a C<:content_cb> in L<LWP::UserAgent>. +=item max_decompressed_size :Int + +Overrides the instance-wide C<max_decompressed_size> given to C<new> for this request. + =back The C<request()> method assumes the first argument to be an instance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/lib/Furl/ZlibStream.pm new/Furl-3.16/lib/Furl/ZlibStream.pm --- old/Furl-3.15/lib/Furl/ZlibStream.pm 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/lib/Furl/ZlibStream.pm 2026-11-06 11:22:58.000000000 +0100 @@ -6,28 +6,68 @@ use Carp (); use Compress::Raw::Zlib qw(Z_OK Z_STREAM_END); +# Compressed input is inflated in slices of this size. DEFLATE expands at +# most ~1032:1, so one inflate() call yields at most a few MB, and the +# size limit is checked before a single call can produce an unbounded +# amount of output (a chunked response can hand us one huge chunk). +my $SLICE = 4096; + sub new { - my ( $class, $buffer ) = @_; + my ( $class, $buffer, $max_size ) = @_; my ( $zlib, $status ) = Compress::Raw::Zlib::Inflate->new( -WindowBits => Compress::Raw::Zlib::WANT_GZIP_OR_ZLIB(), ); $status == Z_OK or Carp::croak("Cannot initialize zlib: $status"); - bless { buffer => $buffer, zlib => $zlib }, $class; + bless { + buffer => $buffer, + zlib => $zlib, + max_size => $max_size, + size => 0, + }, $class; } sub append { my ( $self, $partial ) = @_; - my $status = $self->{zlib}->inflate( $partial, \my $deflated ); - ($status == Z_OK or $status == Z_STREAM_END) - or Carp::croak("Uncompress error: $status"); - $self->{buffer} .= $deflated; + for ( my $offset = 0; $offset < length $partial; $offset += $SLICE ) { + # inflate() consumes its input, so hand it a copy of the slice. + my $input = substr( $partial, $offset, $SLICE ); + my $status = $self->{zlib}->inflate( $input, \my $deflated ); + ($status == Z_OK or $status == Z_STREAM_END) + or Carp::croak("Uncompress error: $status"); + + $self->{size} += length $deflated; + if ( $self->{max_size} && $self->{size} > $self->{max_size} ) { + # Thrown as an object so that Furl::HTTP can tell it apart from + # other exceptions (e.g. one thrown by a write_code callback) + # and turn it into an internal 500 response. + die Furl::ZlibStream::LimitExceeded->new( $self->{max_size} ); + } + $self->{buffer} .= $deflated; + + last if $status == Z_STREAM_END; + } return $self; } sub get_response_string { ref $_[0]->{buffer} ? undef : $_[0]->{buffer} } +package # hide from PAUSE + Furl::ZlibStream::LimitExceeded; +use overload '""' => 'message', fallback => 1; + +sub new { + my ( $class, $max_size ) = @_; + bless { max_size => $max_size }, $class; +} + +sub message { + my $self = shift; + "Decompressed response body exceeds max_decompressed_size" + . " ($self->{max_size} bytes)"; +} + 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/lib/Furl.pm new/Furl-3.16/lib/Furl.pm --- old/Furl-3.15/lib/Furl.pm 2025-09-25 02:25:58.000000000 +0200 +++ new/Furl-3.16/lib/Furl.pm 2026-11-06 11:22:58.000000000 +0100 @@ -6,7 +6,7 @@ use Furl::Request; use Furl::Response; use Carp (); -our $VERSION = '3.15'; +our $VERSION = '3.16'; use 5.008001; @@ -125,6 +125,8 @@ =encoding utf8 +=for stopwords MiB + =head1 NAME Furl - Lightning-fast URL fetcher @@ -178,6 +180,10 @@ =item max_redirects :Int = 7 +=item max_decompressed_size :Int + +Maximum size of a gzip/deflate-decoded response body; C<0> disables the limit. Defaults to 100 MiB for responses held in memory, and to no limit for responses streamed with C<write_file> or C<write_code>. See L<Furl::HTTP/new>. + =item capture_request :Bool = false If this parameter is true, L<Furl::HTTP> captures raw request string. @@ -313,7 +319,7 @@ =over 4 -=item Does Furl depends on XS modules? +=item Does Furl depend on XS modules? No. Although some optional features require XS modules, basic features are available without XS modules. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Furl-3.15/t/300_high/41_max_decompressed_size.t new/Furl-3.16/t/300_high/41_max_decompressed_size.t --- old/Furl-3.15/t/300_high/41_max_decompressed_size.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Furl-3.16/t/300_high/41_max_decompressed_size.t 2026-11-06 11:22:58.000000000 +0100 @@ -0,0 +1,169 @@ +use strict; +use warnings; +use Test::Requires 'Compress::Raw::Zlib'; +use Furl; +use Furl::HTTP; +use IO::Socket::INET; +use Test::TCP; +use Test::More; + +# A small gzip/deflate response must not inflate without bound in memory. +# Once the decoded body passes max_decompressed_size, Furl stops reading and +# returns an internal 500 response. + +use Compress::Raw::Zlib qw(WANT_GZIP MAX_WBITS Z_OK Z_FINISH); + +my $MiB = 1024 * 1024; + +sub compress_zeros { + my ($bytes, $window_bits) = @_; + my ($d, $status) = Compress::Raw::Zlib::Deflate->new( + -WindowBits => $window_bits, -Level => 9); + $status == Z_OK or die "deflate init: $status"; + my $block = "\0" x $MiB; + my $out = ''; + while ($bytes > 0) { + my $in = $bytes >= $MiB ? $block : "\0" x $bytes; + $bytes -= length $in; + $d->deflate($in, my $o); + $out .= $o; + } + $d->flush(my $o, Z_FINISH); + return $out . $o; +} + +my %body = ( + '/small' => do { + my ($d) = Compress::Raw::Zlib::Deflate->new(-WindowBits => WANT_GZIP); + $d->deflate('hello', my $o); + $d->flush(my $t, Z_FINISH); + $o . $t; + }, + '/big' => compress_zeros(2 * $MiB, WANT_GZIP), + '/big-deflate' => compress_zeros(2 * $MiB, MAX_WBITS), + '/big-stream' => compress_zeros(101 * $MiB, WANT_GZIP), +); +# Inflating 100 MiB in memory is too heavy for every smoker. +$body{'/over-default'} = $body{'/big-stream'} if $ENV{AUTHOR_TESTING}; +# Text that compresses to many KB, so it is inflated in many pieces. +my $TEXT = join '', map { "line $_ of the response body\n" } 1 .. 30000; +$body{'/text'} = do { + my ($d) = Compress::Raw::Zlib::Deflate->new(-WindowBits => WANT_GZIP); + $d->deflate($TEXT, my $o); + $d->flush(my $t, Z_FINISH); + $o . $t; +}; +$body{'/text-chunked'} = $body{'/text'}; +$body{'/big-chunked'} = $body{'/big'}; + +test_tcp( + client => sub { + my $port = shift; + my $base = "http://127.0.0.1:$port"; + + my $furl = Furl::HTTP->new(max_decompressed_size => $MiB); + + my (undef, $code, undef, undef, $content) + = $furl->request(url => "$base/small"); + is $code, 200, 'small gzip response under the limit'; + is $content, 'hello', '... decoded'; + + for my $path (qw(/text /text-chunked)) { + (undef, $code, undef, undef, $content) + = $furl->request(url => "$base$path"); + is $code, 200, "$path: larger body under the limit"; + ok $content eq $TEXT, '... decoded intact'; + } + + for my $path (qw(/big /big-deflate /big-chunked)) { + my (undef, $code, $msg, $headers, $content) + = $furl->request(url => "$base$path"); + is $code, 500, "$path: 2 MiB decoded body over a 1 MiB limit is a 500"; + like $msg, qr/max_decompressed_size/, '... with the limit error'; + is {@$headers}->{'X-Internal-Response'}, 1, '... as an internal response'; + } + + my $streamed = 0; + (undef, $code, my $msg) = $furl->request( + url => "$base/big", + write_code => sub { $streamed += length $_[3] }, + ); + is $code, 500, 'an explicit limit applies with write_code'; + like $msg, qr/max_decompressed_size/, '... with the limit error'; + cmp_ok $streamed, '<=', $MiB, '... and stops before the limit'; + + # Other exceptions still propagate. + my $ok = eval { + $furl->request( + url => "$base/small", + write_code => sub { die "callback died\n" }, + ); + 1; + }; + ok !$ok, 'an exception from write_code still propagates'; + is $@, "callback died\n", '... unchanged'; + + (undef, $code, undef, undef, $content) = $furl->request( + url => "$base/big", + max_decompressed_size => 0, + ); + is $code, 200, 'per-request max_decompressed_size => 0 disables the limit'; + is length($content), 2 * $MiB, '... full body decoded'; + + my $res = Furl->new->get("$base/big"); + is $res->code, 200, 'default limit allows an ordinary 2 MiB body'; + is length($res->content), 2 * $MiB, '... full body decoded'; + + # No default limit when streaming: the body does not grow in memory. + $streamed = 0; + $res = Furl->new->request( + url => "$base/big-stream", + write_code => sub { $streamed += length $_[3] }, + ); + is $res->code, 200, 'default limit does not apply with write_code'; + is $streamed, 101 * $MiB, '... full body streamed'; + + SKIP: { + skip 'set AUTHOR_TESTING to inflate 100 MiB in memory', 2 + unless $ENV{AUTHOR_TESTING}; + $res = Furl->new->get("$base/over-default"); + is $res->code, 500, 'default limit (100 MiB) stops a 101 MiB decoded body'; + like $res->message, qr/max_decompressed_size/, '... with the limit error'; + } + + done_testing; + }, + server => sub { + my $port = shift; + local $SIG{PIPE} = 'IGNORE'; + my $sock = IO::Socket::INET->new( + LocalAddr => '127.0.0.1', + LocalPort => $port, + Listen => 5, + ReuseAddr => 1, + ) or die "listen: $!"; + while (my $c = $sock->accept) { + my $req = <$c>; + next unless defined $req; # Test::TCP probing the port + while (defined(my $line = <$c>)) { last if $line eq "\015\012" } + my ($path) = $req =~ m{^\S+ (\S+)}; + my $payload = $body{$path}; + my $encoding = $path eq '/big-deflate' ? 'deflate' : 'gzip'; + if ($path =~ /-chunked\z/) { + print {$c} "HTTP/1.1 200 OK\015\012", + "Content-Encoding: $encoding\015\012", + "Transfer-Encoding: chunked\015\012", + "Connection: close\015\012\015\012", + sprintf("%x\015\012", length $payload), $payload, + "\015\012", "0\015\012\015\012"; + } + else { + print {$c} "HTTP/1.1 200 OK\015\012", + "Content-Encoding: $encoding\015\012", + "Content-Length: ", length($payload), "\015\012", + "Connection: close\015\012\015\012", $payload; + } + close $c; + } + }, +); ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.zDGvg5/_old 2026-11-10 16:30:24.158748350 +0100 +++ /var/tmp/diff_new_pack.zDGvg5/_new 2026-11-10 16:30:24.172748936 +0100 @@ -1,6 +1,6 @@ -mtime: 1759771260 -commit: 8f10239077d874d86e0a8e48a3c29b09c23f70c3d957ee2a4eb01c3dde3541f7 -url: https://src.opensuse.org/perl/perl-Furl.git -revision: 8f10239077d874d86e0a8e48a3c29b09c23f70c3d957ee2a4eb01c3dde3541f7 +mtime: 1794319226 +commit: e3457169ae6f9f88e54c6988d6f7645fb6035d199ce007427ea3fcc1306c30b6 +url: https://src.opensuse.org/perl/perl-Furl +revision: e3457169ae6f9f88e54c6988d6f7645fb6035d199ce007427ea3fcc1306c30b6 projectscmsync: https://src.opensuse.org/perl/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-11-10 15:00:26.000000000 +0100 @@ -0,0 +1 @@ +.osc
