Package: libcurl4t64 Version: 8.7.1-2 Severity: important Tags: upstream patch Forwarded: https://github.com/curl/curl/issues/13269
Dear Maintainer, curl 8.7 no longer fills in the request_size field. This has been reported upstream in the following issue: https://github.com/curl/curl/issues/13269 This causes at least ruby-ethon, a Ruby library that wraps libcurl via FFI, to fail its test suite (after fixing it to not hardcode libcurl4 as a dependency), like this: ----------------8<----------------8<----------------8<----------------- Failures: 1) Ethon::Easy::Informations#request_size returns 53 Failure/Error: expect(easy.request_size).to eq(53) expected: 53 got: 0 (compared using ==) # ./spec/ethon/easy/informations_spec.rb:92:in `block (3 levels) in <top (required)>' Finished in 5.06 seconds (files took 0.80166 seconds to load) 578 examples, 1 failure, 2 pending Failed examples: rspec ./spec/ethon/easy/informations_spec.rb:91 # Ethon::Easy::Informations#request_size returns 53 ----------------8<----------------8<----------------8<----------------- (the same test suite passes just fine against libcurl4 8.6.0-3 from testing.) I have tested the patch in https://github.com/curl/curl/pull/13275 and it indeed fixes this. I'm including a patch against the Debian package in the archive that includes this patch in debian/patches, with the fuzzyness already removed, and updates debian/patches/series accordingly. -- System Information: Debian Release: trixie/sid APT prefers testing APT policy: (900, 'testing'), (500, 'stable-security'), (500, 'unstable'), (1, 'experimental') Architecture: arm64 (aarch64) Kernel: Linux 6.6.15-arm64 (SMP w/32 CPU threads) Locale: LANG=pt_BR.UTF-8, LC_CTYPE=pt_BR.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /usr/bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages libcurl4t64 depends on: ii libbrotli1 1.1.0-2+b3 ii libc6 2.37-15 ii libgssapi-krb5-2 1.20.1-5+b1 ii libidn2-0 2.3.7-2 ii libldap-2.5-0 2.5.13+dfsg-5+b3 ii libnghttp2-14 1.59.0-1 pn libpsl5t64 <none> ii librtmp1 2.4+20151223.gitfa8646d.1-2+b2 pn libssh2-1t64 <none> pn libssl3t64 <none> ii libzstd1 1.5.5+dfsg2-2 ii zlib1g 1:1.3.dfsg-3+b1 Versions of packages libcurl4t64 recommends: ii ca-certificates 20240203 libcurl4t64 suggests no packages.
diff -Nru curl-8.7.1/debian/patches/Fix_CURLINFO_REQUEST_SIZE.patch curl-8.7.1/debian/patches/Fix_CURLINFO_REQUEST_SIZE.patch --- curl-8.7.1/debian/patches/Fix_CURLINFO_REQUEST_SIZE.patch 1970-01-01 00:00:00.000000000 +0000 +++ curl-8.7.1/debian/patches/Fix_CURLINFO_REQUEST_SIZE.patch 2024-04-19 13:18:39.000000000 +0000 @@ -0,0 +1,210 @@ +From 2793acbfc5e89fb130b1d4e045cb6cd7b6549412 Mon Sep 17 00:00:00 2001 +From: Stefan Eissing <ste...@eissing.org> +Date: Thu, 4 Apr 2024 11:06:06 +0200 +Subject: [PATCH] Fix CURLINFO_REQUEST_SIZE, add tests for transfer infos + reported + +- refs #13269 +- tests for 'size_request' and other stats reported, for + presence and consistency +--- + lib/transfer.c | 3 + + tests/http/test_16_info.py | 162 ++++++++++++++++++++++++++++++++++++ + tests/http/testenv/httpd.py | 1 + + 3 files changed, 166 insertions(+) + create mode 100644 tests/http/test_16_info.py + +Index: curl-8.7.1/lib/transfer.c +=================================================================== +--- curl-8.7.1.orig/lib/transfer.c ++++ curl-8.7.1/lib/transfer.c +@@ -1221,6 +1221,9 @@ CURLcode Curl_xfer_send(struct Curl_easy + result = CURLE_OK; + *pnwritten = 0; + } ++ else if(!result && *pnwritten) ++ data->info.request_size += *pnwritten; ++ + return result; + } + +Index: curl-8.7.1/tests/http/test_16_info.py +=================================================================== +--- /dev/null ++++ curl-8.7.1/tests/http/test_16_info.py +@@ -0,0 +1,162 @@ ++#!/usr/bin/env python3 ++# -*- coding: utf-8 -*- ++#*************************************************************************** ++# _ _ ____ _ ++# Project ___| | | | _ \| | ++# / __| | | | |_) | | ++# | (__| |_| | _ <| |___ ++# \___|\___/|_| \_\_____| ++# ++# Copyright (C) Daniel Stenberg, <dan...@haxx.se>, et al. ++# ++# This software is licensed as described in the file COPYING, which ++# you should have received as part of this distribution. The terms ++# are also available at https://curl.se/docs/copyright.html. ++# ++# You may opt to use, copy, modify, merge, publish, distribute and/or sell ++# copies of the Software, and permit persons to whom the Software is ++# furnished to do so, under the terms of the COPYING file. ++# ++# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++# KIND, either express or implied. ++# ++# SPDX-License-Identifier: curl ++# ++########################################################################### ++# ++import difflib ++import filecmp ++import logging ++import os ++from datetime import timedelta ++import pytest ++ ++from testenv import Env, CurlClient, LocalClient, ExecResult ++ ++ ++log = logging.getLogger(__name__) ++ ++ ++class TestInfo: ++ ++ @pytest.fixture(autouse=True, scope='class') ++ def _class_scope(self, env, httpd, nghttpx): ++ if env.have_h3(): ++ nghttpx.start_if_needed() ++ httpd.clear_extra_configs() ++ httpd.reload() ++ ++ @pytest.fixture(autouse=True, scope='class') ++ def _class_scope(self, env, httpd): ++ indir = httpd.docs_dir ++ env.make_data_file(indir=indir, fname="data-10k", fsize=10*1024) ++ env.make_data_file(indir=indir, fname="data-100k", fsize=100*1024) ++ env.make_data_file(indir=indir, fname="data-1m", fsize=1024*1024) ++ ++ # download plain file ++ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) ++ def test_16_01_info_download(self, env: Env, httpd, nghttpx, repeat, proto): ++ if proto == 'h3' and not env.have_h3(): ++ pytest.skip("h3 not supported") ++ count = 2 ++ curl = CurlClient(env=env) ++ url = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' ++ r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True) ++ r.check_stats(count=count, http_status=200) ++ for s in r.stats: ++ self.check_stat(s, dl_size=30, ul_size=0) ++ ++ # download plain file with a 302 redirect ++ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) ++ def test_16_02_info_302_download(self, env: Env, httpd, nghttpx, repeat, proto): ++ if proto == 'h3' and not env.have_h3(): ++ pytest.skip("h3 not supported") ++ count = 2 ++ curl = CurlClient(env=env) ++ url = f'https://{env.authority_for(env.domain1, proto)}/data.json.302?[0-{count-1}]' ++ r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True, extra_args=[ ++ '--location' ++ ]) ++ r.check_stats(count=count, http_status=200) ++ for s in r.stats: ++ self.check_stat(s, dl_size=30, ul_size=0) ++ ++ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) ++ def test_16_03_info_upload(self, env: Env, httpd, nghttpx, proto, repeat): ++ if proto == 'h3' and not env.have_h3(): ++ pytest.skip("h3 not supported") ++ count = 2 ++ fdata = os.path.join(env.gen_dir, 'data-100k') ++ fsize = 100 * 1024 ++ curl = CurlClient(env=env) ++ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' ++ r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, ++ with_headers=True) ++ r.check_response(count=count, http_status=200) ++ r.check_stats(count=count, http_status=200) ++ for s in r.stats: ++ self.check_stat(s, dl_size=fsize, ul_size=fsize) ++ ++ # download plain file via http: ('time_appconnect' is 0) ++ @pytest.mark.parametrize("proto", ['http/1.1']) ++ def test_16_04_info_http_download(self, env: Env, httpd, nghttpx, repeat, proto): ++ count = 2 ++ curl = CurlClient(env=env) ++ url = f'http://{env.domain1}:{env.http_port}/data.json?[0-{count-1}]' ++ r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True) ++ r.check_stats(count=count, http_status=200) ++ for s in r.stats: ++ self.check_stat(s, dl_size=30, ul_size=0) ++ ++ def check_stat(self, s, dl_size=None, ul_size=None): ++ self.check_stat_times(s) ++ # we always send something ++ self.check_stat_positive(s, 'size_request') ++ # we always receive response headers ++ self.check_stat_positive(s, 'size_header') ++ if ul_size is not None: ++ assert s['size_upload'] == ul_size # the file we sent ++ assert s['size_request'] >= s['size_upload'], f'"size_request" smaller than "size_upload", {s}' ++ if dl_size is not None: ++ assert s['size_download'] == dl_size # the file we received ++ ++ def check_stat_positive(self, s, key): ++ assert key in s, f'stat "{key}" missing: {s}' ++ assert s[key] > 0, f'stat "{key}" not positive: {s}' ++ ++ def check_stat_zero(self, s, key): ++ assert key in s, f'stat "{key}" missing: {s}' ++ assert s[key] == 0, f'stat "{key}" not zero: {s}' ++ ++ def check_stat_times(self, s): ++ # check timings reported on a transfer for consistency ++ url = s['url_effective'] ++ # all stat keys which reporting timings ++ all_keys = set([ ++ 'time_appconnect', 'time_connect', 'time_redirect', ++ 'time_pretransfer', 'time_starttransfer', 'time_total' ++ ]) ++ # stat keys where we expect a positive value ++ pos_keys = set(['time_pretransfer', 'time_starttransfer', 'time_total']) ++ if s['num_connects'] > 0: ++ pos_keys.add('time_connect') ++ if url.startswith('https:'): ++ pos_keys.add('time_appconnect') ++ if s['num_redirects'] > 0: ++ pos_keys.add('time_redirect') ++ zero_keys = all_keys - pos_keys ++ # assert all zeros are zeros and the others are positive ++ for key in zero_keys: ++ self.check_stat_zero(s, key) ++ for key in pos_keys: ++ self.check_stat_positive(s, key) ++ # assert that all timers before "time_pretransfer" are less or equal ++ for key in ['time_appconnect', 'time_connect', 'time_namelookup']: ++ assert s[key] < s['time_pretransfer'], f'time "{key}" larger than' \ ++ f'"time_pretransfer": {s}' ++ # assert transfer start is after pretransfer ++ assert s['time_pretransfer'] <= s['time_starttransfer'], f'"time_pretransfer" '\ ++ f'greater than "time_starttransfer", {s}' ++ # assert that transfer start is before total ++ assert s['time_starttransfer'] <= s['time_total'], f'"time_starttransfer" '\ ++ f'greater than "time_total", {s}' +\ No newline at end of file +Index: curl-8.7.1/tests/http/testenv/httpd.py +=================================================================== +--- curl-8.7.1.orig/tests/http/testenv/httpd.py ++++ curl-8.7.1/tests/http/testenv/httpd.py +@@ -372,6 +372,7 @@ class Httpd: + lines = [] + if Httpd.MOD_CURLTEST is not None: + lines.extend([ ++ f' Redirect 302 /data.json.302 /data.json', + f' Redirect 301 /curltest/echo301 /curltest/echo', + f' Redirect 302 /curltest/echo302 /curltest/echo', + f' Redirect 303 /curltest/echo303 /curltest/echo', diff -Nru curl-8.7.1/debian/patches/series curl-8.7.1/debian/patches/series --- curl-8.7.1/debian/patches/series 2024-04-03 17:59:41.000000000 +0000 +++ curl-8.7.1/debian/patches/series 2024-04-19 13:18:20.000000000 +0000 @@ -9,6 +9,7 @@ make-manpages-reproducible.patch fix-regression-on-chunked-post.patch test1901_verify_chunked_POST_from_callback_with_CURLOPT_POSTFIELDSIZ.patch +Fix_CURLINFO_REQUEST_SIZE.patch # Do not add patches below. # Used to generate packages for the other crypto libraries.
signature.asc
Description: PGP signature