From b9c036e9f7c749ec20766eebb35d41f9704e49f0 Mon Sep 17 00:00:00 2001 From: Yifei Kong Date: Wed, 27 Nov 2024 16:43:09 +0800 Subject: [PATCH] Revert 8.11.0 docs --- chrome/patches/curl-impersonate.patch | 97156 +----------------------- 1 file changed, 4074 insertions(+), 93082 deletions(-) diff --git a/chrome/patches/curl-impersonate.patch b/chrome/patches/curl-impersonate.patch index 7655dc86..ae9bde68 100644 --- a/chrome/patches/curl-impersonate.patch +++ b/chrome/patches/curl-impersonate.patch @@ -144,93420 +144,4412 @@ index 54f92d931..ea5895e9b 100644 else echo "curl was built with static libraries disabled" >&2 exit 1 -diff --git a/docs/.gitignore b/docs/.gitignore -index a087be744..31ca7656e 100644 ---- a/docs/.gitignore -+++ b/docs/.gitignore -@@ -4,3 +4,4 @@ - - *.1 - *.3 -+RELEASE-TOOLS.md.dist -diff --git a/docs/BINDINGS.md b/docs/BINDINGS.md -index 060586fde..e6287761b 100644 ---- a/docs/BINDINGS.md -+++ b/docs/BINDINGS.md -@@ -1,3 +1,9 @@ -+ -+ - libcurl bindings - ================ - -@@ -57,7 +63,7 @@ Go: [go-curl](https://github.com/andelf/go-curl) by ShuYu Wang - - [Hollywood](https://www.hollywood-mal.com/download.html) hURL by Andreas Falkenhahn - --[Java](https://github.com/pjlegato/curl-java) -+[Java](https://github.com/covers1624/curl4j) - - [Julia](https://github.com/JuliaWeb/LibCURL.jl) Written by Amit Murthy - -@@ -138,3 +144,5 @@ Ruby: [curb](https://github.com/taf2/curb) written by Ross Bamford, - [XBLite](https://web.archive.org/web/20060426150418/perso.wanadoo.fr/xblite/libraries.html) Written by David Szafranski - - [Xojo](https://github.com/charonn0/RB-libcURL) Written by Andrew Lambert -+ -+[Zig](https://github.com/jiacai2050/zig-curl) Written by Jiacai Liu, both easy and multi API are supported. -diff --git a/docs/BUG-BOUNTY.md b/docs/BUG-BOUNTY.md -index 3cb4024a3..399c4cfe1 100644 ---- a/docs/BUG-BOUNTY.md -+++ b/docs/BUG-BOUNTY.md -@@ -1,3 +1,9 @@ -+ -+ - # The curl bug bounty - - The curl project runs a bug bounty program in association with -@@ -61,6 +67,13 @@ infrastructure. - The curl security team is the sole arbiter if a reported flaw is subject to a - bounty or not. - -+## Third parties -+ -+The curl bug bounty does not cover flaws in third party dependencies -+(libraries) used by curl or libcurl. If the bug triggers because of curl -+behaving wrongly or abusing a third party dependency, the problem is rather in -+curl and not in the dependency and then the bounty might cover the problem. -+ - ## How are vulnerabilities graded? - - The grading of each reported vulnerability that makes a reward claim is -diff --git a/docs/BUGS.md b/docs/BUGS.md -index 9a3a30add..8a3ef82e9 100644 ---- a/docs/BUGS.md -+++ b/docs/BUGS.md -@@ -1,3 +1,9 @@ -+ -+ - # BUGS - - ## There are still bugs -diff --git a/docs/CIPHERS-TLS12.md b/docs/CIPHERS-TLS12.md -new file mode 100644 -index 000000000..d67c62ba7 +diff --git a/export.sh b/export.sh +new file mode 100755 +index 000000000..7bced6879 --- /dev/null -+++ b/docs/CIPHERS-TLS12.md -@@ -0,0 +1,336 @@ -+ ++++ b/export.sh +@@ -0,0 +1,9 @@ ++#!/bin/bash + -+# TLS 1.2 cipher suites ++# TODO: use cmake to generate mingw makefile, see: ++# ++# 1. https://github.com/curl/curl/pull/13244/files ++# 2. https://everything.curl.dev/build/windows.html + -+| Id | IANA name | OpenSSL name | RFC | -+|--------|-----------------------------------------------|------------------------------------|--------------------| -+| 0x0001 | TLS_RSA_WITH_NULL_MD5 | NULL-MD5 | [RFC5246] | -+| 0x0002 | TLS_RSA_WITH_NULL_SHA | NULL-SHA | [RFC5246] | -+| 0x0003 | TLS_RSA_EXPORT_WITH_RC4_40_MD5 | EXP-RC4-MD5 | [RFC4346][RFC6347] | -+| 0x0004 | TLS_RSA_WITH_RC4_128_MD5 | RC4-MD5 | [RFC5246][RFC6347] | -+| 0x0005 | TLS_RSA_WITH_RC4_128_SHA | RC4-SHA | [RFC5246][RFC6347] | -+| 0x0006 | TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 | EXP-RC2-CBC-MD5 | [RFC4346] | -+| 0x0007 | TLS_RSA_WITH_IDEA_CBC_SHA | IDEA-CBC-SHA | [RFC8996] | -+| 0x0008 | TLS_RSA_EXPORT_WITH_DES40_CBC_SHA | EXP-DES-CBC-SHA | [RFC4346] | -+| 0x0009 | TLS_RSA_WITH_DES_CBC_SHA | DES-CBC-SHA | [RFC8996] | -+| 0x000A | TLS_RSA_WITH_3DES_EDE_CBC_SHA | DES-CBC3-SHA | [RFC5246] | -+| 0x000B | TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA | EXP-DH-DSS-DES-CBC-SHA | [RFC4346] | -+| 0x000C | TLS_DH_DSS_WITH_DES_CBC_SHA | DH-DSS-DES-CBC-SHA | [RFC8996] | -+| 0x000D | TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA | DH-DSS-DES-CBC3-SHA | [RFC5246] | -+| 0x000E | TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA | EXP-DH-RSA-DES-CBC-SHA | [RFC4346] | -+| 0x000F | TLS_DH_RSA_WITH_DES_CBC_SHA | DH-RSA-DES-CBC-SHA | [RFC8996] | -+| 0x0010 | TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA | DH-RSA-DES-CBC3-SHA | [RFC5246] | -+| 0x0011 | TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA | EXP-DHE-DSS-DES-CBC-SHA | [RFC4346] | -+| 0x0012 | TLS_DHE_DSS_WITH_DES_CBC_SHA | DHE-DSS-DES-CBC-SHA | [RFC8996] | -+| 0x0013 | TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA | DHE-DSS-DES-CBC3-SHA | [RFC5246] | -+| 0x0014 | TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA | EXP-DHE-RSA-DES-CBC-SHA | [RFC4346] | -+| 0x0015 | TLS_DHE_RSA_WITH_DES_CBC_SHA | DHE-RSA-DES-CBC-SHA | [RFC8996] | -+| 0x0016 | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA | DHE-RSA-DES-CBC3-SHA | [RFC5246] | -+| 0x0017 | TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 | EXP-ADH-RC4-MD5 | [RFC4346][RFC6347] | -+| 0x0018 | TLS_DH_anon_WITH_RC4_128_MD5 | ADH-RC4-MD5 | [RFC5246][RFC6347] | -+| 0x0019 | TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA | EXP-ADH-DES-CBC-SHA | [RFC4346] | -+| 0x001A | TLS_DH_anon_WITH_DES_CBC_SHA | ADH-DES-CBC-SHA | [RFC8996] | -+| 0x001B | TLS_DH_anon_WITH_3DES_EDE_CBC_SHA | ADH-DES-CBC3-SHA | [RFC5246] | -+| 0x001C | | FZA-NULL-SHA | | -+| 0x001D | | FZA-FZA-CBC-SHA | | -+| 0x001E | TLS_KRB5_WITH_DES_CBC_SHA | KRB5-DES-CBC-SHA | [RFC2712] | -+| 0x001F | TLS_KRB5_WITH_3DES_EDE_CBC_SHA | KRB5-DES-CBC3-SHA | [RFC2712] | -+| 0x0020 | TLS_KRB5_WITH_RC4_128_SHA | KRB5-RC4-SHA | [RFC2712][RFC6347] | -+| 0x0021 | TLS_KRB5_WITH_IDEA_CBC_SHA | KRB5-IDEA-CBC-SHA | [RFC2712] | -+| 0x0022 | TLS_KRB5_WITH_DES_CBC_MD5 | KRB5-DES-CBC-MD5 | [RFC2712] | -+| 0x0023 | TLS_KRB5_WITH_3DES_EDE_CBC_MD5 | KRB5-DES-CBC3-MD5 | [RFC2712] | -+| 0x0024 | TLS_KRB5_WITH_RC4_128_MD5 | KRB5-RC4-MD5 | [RFC2712][RFC6347] | -+| 0x0025 | TLS_KRB5_WITH_IDEA_CBC_MD5 | KRB5-IDEA-CBC-MD5 | [RFC2712] | -+| 0x0026 | TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA | EXP-KRB5-DES-CBC-SHA | [RFC2712] | -+| 0x0027 | TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA | EXP-KRB5-RC2-CBC-SHA | [RFC2712] | -+| 0x0028 | TLS_KRB5_EXPORT_WITH_RC4_40_SHA | EXP-KRB5-RC4-SHA | [RFC2712][RFC6347] | -+| 0x0029 | TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 | EXP-KRB5-DES-CBC-MD5 | [RFC2712] | -+| 0x002A | TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 | EXP-KRB5-RC2-CBC-MD5 | [RFC2712] | -+| 0x002B | TLS_KRB5_EXPORT_WITH_RC4_40_MD5 | EXP-KRB5-RC4-MD5 | [RFC2712][RFC6347] | -+| 0x002C | TLS_PSK_WITH_NULL_SHA | PSK-NULL-SHA | [RFC4785] | -+| 0x002D | TLS_DHE_PSK_WITH_NULL_SHA | DHE-PSK-NULL-SHA | [RFC4785] | -+| 0x002E | TLS_RSA_PSK_WITH_NULL_SHA | RSA-PSK-NULL-SHA | [RFC4785] | -+| 0x002F | TLS_RSA_WITH_AES_128_CBC_SHA | AES128-SHA | [RFC5246] | -+| 0x0030 | TLS_DH_DSS_WITH_AES_128_CBC_SHA | DH-DSS-AES128-SHA | [RFC5246] | -+| 0x0031 | TLS_DH_RSA_WITH_AES_128_CBC_SHA | DH-RSA-AES128-SHA | [RFC5246] | -+| 0x0032 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA | DHE-DSS-AES128-SHA | [RFC5246] | -+| 0x0033 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA | DHE-RSA-AES128-SHA | [RFC5246] | -+| 0x0034 | TLS_DH_anon_WITH_AES_128_CBC_SHA | ADH-AES128-SHA | [RFC5246] | -+| 0x0035 | TLS_RSA_WITH_AES_256_CBC_SHA | AES256-SHA | [RFC5246] | -+| 0x0036 | TLS_DH_DSS_WITH_AES_256_CBC_SHA | DH-DSS-AES256-SHA | [RFC5246] | -+| 0x0037 | TLS_DH_RSA_WITH_AES_256_CBC_SHA | DH-RSA-AES256-SHA | [RFC5246] | -+| 0x0038 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA | DHE-DSS-AES256-SHA | [RFC5246] | -+| 0x0039 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA | DHE-RSA-AES256-SHA | [RFC5246] | -+| 0x003A | TLS_DH_anon_WITH_AES_256_CBC_SHA | ADH-AES256-SHA | [RFC5246] | -+| 0x003B | TLS_RSA_WITH_NULL_SHA256 | NULL-SHA256 | [RFC5246] | -+| 0x003C | TLS_RSA_WITH_AES_128_CBC_SHA256 | AES128-SHA256 | [RFC5246] | -+| 0x003D | TLS_RSA_WITH_AES_256_CBC_SHA256 | AES256-SHA256 | [RFC5246] | -+| 0x003E | TLS_DH_DSS_WITH_AES_128_CBC_SHA256 | DH-DSS-AES128-SHA256 | [RFC5246] | -+| 0x003F | TLS_DH_RSA_WITH_AES_128_CBC_SHA256 | DH-RSA-AES128-SHA256 | [RFC5246] | -+| 0x0040 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 | DHE-DSS-AES128-SHA256 | [RFC5246] | -+| 0x0041 | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA | CAMELLIA128-SHA | [RFC5932] | -+| 0x0042 | TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA | DH-DSS-CAMELLIA128-SHA | [RFC5932] | -+| 0x0043 | TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA | DH-RSA-CAMELLIA128-SHA | [RFC5932] | -+| 0x0044 | TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA | DHE-DSS-CAMELLIA128-SHA | [RFC5932] | -+| 0x0045 | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA | DHE-RSA-CAMELLIA128-SHA | [RFC5932] | -+| 0x0046 | TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA | ADH-CAMELLIA128-SHA | [RFC5932] | -+| 0x0060 | | EXP1024-RC4-MD5 | | -+| 0x0061 | | EXP1024-RC2-CBC-MD5 | | -+| 0x0062 | | EXP1024-DES-CBC-SHA | | -+| 0x0063 | | EXP1024-DHE-DSS-DES-CBC-SHA | | -+| 0x0064 | | EXP1024-RC4-SHA | | -+| 0x0065 | | EXP1024-DHE-DSS-RC4-SHA | | -+| 0x0066 | | DHE-DSS-RC4-SHA | | -+| 0x0067 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 | DHE-RSA-AES128-SHA256 | [RFC5246] | -+| 0x0068 | TLS_DH_DSS_WITH_AES_256_CBC_SHA256 | DH-DSS-AES256-SHA256 | [RFC5246] | -+| 0x0069 | TLS_DH_RSA_WITH_AES_256_CBC_SHA256 | DH-RSA-AES256-SHA256 | [RFC5246] | -+| 0x006A | TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 | DHE-DSS-AES256-SHA256 | [RFC5246] | -+| 0x006B | TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 | DHE-RSA-AES256-SHA256 | [RFC5246] | -+| 0x006C | TLS_DH_anon_WITH_AES_128_CBC_SHA256 | ADH-AES128-SHA256 | [RFC5246] | -+| 0x006D | TLS_DH_anon_WITH_AES_256_CBC_SHA256 | ADH-AES256-SHA256 | [RFC5246] | -+| 0x0080 | | GOST94-GOST89-GOST89 | | -+| 0x0081 | | GOST2001-GOST89-GOST89 | | -+| 0x0082 | | GOST94-NULL-GOST94 | | -+| 0x0083 | | GOST2001-NULL-GOST94 | | -+| 0x0084 | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA | CAMELLIA256-SHA | [RFC5932] | -+| 0x0085 | TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA | DH-DSS-CAMELLIA256-SHA | [RFC5932] | -+| 0x0086 | TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA | DH-RSA-CAMELLIA256-SHA | [RFC5932] | -+| 0x0087 | TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA | DHE-DSS-CAMELLIA256-SHA | [RFC5932] | -+| 0x0088 | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA | DHE-RSA-CAMELLIA256-SHA | [RFC5932] | -+| 0x0089 | TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA | ADH-CAMELLIA256-SHA | [RFC5932] | -+| 0x008A | TLS_PSK_WITH_RC4_128_SHA | PSK-RC4-SHA | [RFC4279][RFC6347] | -+| 0x008B | TLS_PSK_WITH_3DES_EDE_CBC_SHA | PSK-3DES-EDE-CBC-SHA | [RFC4279] | -+| 0x008C | TLS_PSK_WITH_AES_128_CBC_SHA | PSK-AES128-CBC-SHA | [RFC4279] | -+| 0x008D | TLS_PSK_WITH_AES_256_CBC_SHA | PSK-AES256-CBC-SHA | [RFC4279] | -+| 0x008E | TLS_DHE_PSK_WITH_RC4_128_SHA | DHE-PSK-RC4-SHA | [RFC4279][RFC6347] | -+| 0x008F | TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA | DHE-PSK-3DES-EDE-CBC-SHA | [RFC4279] | -+| 0x0090 | TLS_DHE_PSK_WITH_AES_128_CBC_SHA | DHE-PSK-AES128-CBC-SHA | [RFC4279] | -+| 0x0091 | TLS_DHE_PSK_WITH_AES_256_CBC_SHA | DHE-PSK-AES256-CBC-SHA | [RFC4279] | -+| 0x0092 | TLS_RSA_PSK_WITH_RC4_128_SHA | RSA-PSK-RC4-SHA | [RFC4279][RFC6347] | -+| 0x0093 | TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA | RSA-PSK-3DES-EDE-CBC-SHA | [RFC4279] | -+| 0x0094 | TLS_RSA_PSK_WITH_AES_128_CBC_SHA | RSA-PSK-AES128-CBC-SHA | [RFC4279] | -+| 0x0095 | TLS_RSA_PSK_WITH_AES_256_CBC_SHA | RSA-PSK-AES256-CBC-SHA | [RFC4279] | -+| 0x0096 | TLS_RSA_WITH_SEED_CBC_SHA | SEED-SHA | [RFC4162] | -+| 0x0097 | TLS_DH_DSS_WITH_SEED_CBC_SHA | DH-DSS-SEED-SHA | [RFC4162] | -+| 0x0098 | TLS_DH_RSA_WITH_SEED_CBC_SHA | DH-RSA-SEED-SHA | [RFC4162] | -+| 0x0099 | TLS_DHE_DSS_WITH_SEED_CBC_SHA | DHE-DSS-SEED-SHA | [RFC4162] | -+| 0x009A | TLS_DHE_RSA_WITH_SEED_CBC_SHA | DHE-RSA-SEED-SHA | [RFC4162] | -+| 0x009B | TLS_DH_anon_WITH_SEED_CBC_SHA | ADH-SEED-SHA | [RFC4162] | -+| 0x009C | TLS_RSA_WITH_AES_128_GCM_SHA256 | AES128-GCM-SHA256 | [RFC5288] | -+| 0x009D | TLS_RSA_WITH_AES_256_GCM_SHA384 | AES256-GCM-SHA384 | [RFC5288] | -+| 0x009E | TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 | DHE-RSA-AES128-GCM-SHA256 | [RFC5288] | -+| 0x009F | TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 | DHE-RSA-AES256-GCM-SHA384 | [RFC5288] | -+| 0x00A0 | TLS_DH_RSA_WITH_AES_128_GCM_SHA256 | DH-RSA-AES128-GCM-SHA256 | [RFC5288] | -+| 0x00A1 | TLS_DH_RSA_WITH_AES_256_GCM_SHA384 | DH-RSA-AES256-GCM-SHA384 | [RFC5288] | -+| 0x00A2 | TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 | DHE-DSS-AES128-GCM-SHA256 | [RFC5288] | -+| 0x00A3 | TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 | DHE-DSS-AES256-GCM-SHA384 | [RFC5288] | -+| 0x00A4 | TLS_DH_DSS_WITH_AES_128_GCM_SHA256 | DH-DSS-AES128-GCM-SHA256 | [RFC5288] | -+| 0x00A5 | TLS_DH_DSS_WITH_AES_256_GCM_SHA384 | DH-DSS-AES256-GCM-SHA384 | [RFC5288] | -+| 0x00A6 | TLS_DH_anon_WITH_AES_128_GCM_SHA256 | ADH-AES128-GCM-SHA256 | [RFC5288] | -+| 0x00A7 | TLS_DH_anon_WITH_AES_256_GCM_SHA384 | ADH-AES256-GCM-SHA384 | [RFC5288] | -+| 0x00A8 | TLS_PSK_WITH_AES_128_GCM_SHA256 | PSK-AES128-GCM-SHA256 | [RFC5487] | -+| 0x00A9 | TLS_PSK_WITH_AES_256_GCM_SHA384 | PSK-AES256-GCM-SHA384 | [RFC5487] | -+| 0x00AA | TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 | DHE-PSK-AES128-GCM-SHA256 | [RFC5487] | -+| 0x00AB | TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 | DHE-PSK-AES256-GCM-SHA384 | [RFC5487] | -+| 0x00AC | TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 | RSA-PSK-AES128-GCM-SHA256 | [RFC5487] | -+| 0x00AD | TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 | RSA-PSK-AES256-GCM-SHA384 | [RFC5487] | -+| 0x00AE | TLS_PSK_WITH_AES_128_CBC_SHA256 | PSK-AES128-CBC-SHA256 | [RFC5487] | -+| 0x00AF | TLS_PSK_WITH_AES_256_CBC_SHA384 | PSK-AES256-CBC-SHA384 | [RFC5487] | -+| 0x00B0 | TLS_PSK_WITH_NULL_SHA256 | PSK-NULL-SHA256 | [RFC5487] | -+| 0x00B1 | TLS_PSK_WITH_NULL_SHA384 | PSK-NULL-SHA384 | [RFC5487] | -+| 0x00B2 | TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 | DHE-PSK-AES128-CBC-SHA256 | [RFC5487] | -+| 0x00B3 | TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 | DHE-PSK-AES256-CBC-SHA384 | [RFC5487] | -+| 0x00B4 | TLS_DHE_PSK_WITH_NULL_SHA256 | DHE-PSK-NULL-SHA256 | [RFC5487] | -+| 0x00B5 | TLS_DHE_PSK_WITH_NULL_SHA384 | DHE-PSK-NULL-SHA384 | [RFC5487] | -+| 0x00B6 | TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 | RSA-PSK-AES128-CBC-SHA256 | [RFC5487] | -+| 0x00B7 | TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 | RSA-PSK-AES256-CBC-SHA384 | [RFC5487] | -+| 0x00B8 | TLS_RSA_PSK_WITH_NULL_SHA256 | RSA-PSK-NULL-SHA256 | [RFC5487] | -+| 0x00B9 | TLS_RSA_PSK_WITH_NULL_SHA384 | RSA-PSK-NULL-SHA384 | [RFC5487] | -+| 0x00BA | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 | CAMELLIA128-SHA256 | [RFC5932] | -+| 0x00BD | TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 | DHE-DSS-CAMELLIA128-SHA256 | [RFC5932] | -+| 0x00BE | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 | DHE-RSA-CAMELLIA128-SHA256 | [RFC5932] | -+| 0x00BF | TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 | ADH-CAMELLIA128-SHA256 | [RFC5932] | -+| 0x00C0 | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 | CAMELLIA256-SHA256 | [RFC5932] | -+| 0x00C3 | TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 | DHE-DSS-CAMELLIA256-SHA256 | [RFC5932] | -+| 0x00C4 | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 | DHE-RSA-CAMELLIA256-SHA256 | [RFC5932] | -+| 0x00C5 | TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 | ADH-CAMELLIA256-SHA256 | [RFC5932] | -+| 0x00FF | TLS_EMPTY_RENEGOTIATION_INFO_SCSV | | [RFC5746] | -+| 0x5600 | TLS_FALLBACK_SCSV | | [RFC7507] | -+| 0xC001 | TLS_ECDH_ECDSA_WITH_NULL_SHA | ECDH-ECDSA-NULL-SHA | [RFC8422] | -+| 0xC002 | TLS_ECDH_ECDSA_WITH_RC4_128_SHA | ECDH-ECDSA-RC4-SHA | [RFC8422][RFC6347] | -+| 0xC003 | TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA | ECDH-ECDSA-DES-CBC3-SHA | [RFC8422] | -+| 0xC004 | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA | ECDH-ECDSA-AES128-SHA | [RFC8422] | -+| 0xC005 | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA | ECDH-ECDSA-AES256-SHA | [RFC8422] | -+| 0xC006 | TLS_ECDHE_ECDSA_WITH_NULL_SHA | ECDHE-ECDSA-NULL-SHA | [RFC8422] | -+| 0xC007 | TLS_ECDHE_ECDSA_WITH_RC4_128_SHA | ECDHE-ECDSA-RC4-SHA | [RFC8422][RFC6347] | -+| 0xC008 | TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA | ECDHE-ECDSA-DES-CBC3-SHA | [RFC8422] | -+| 0xC009 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA | ECDHE-ECDSA-AES128-SHA | [RFC8422] | -+| 0xC00A | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA | ECDHE-ECDSA-AES256-SHA | [RFC8422] | -+| 0xC00B | TLS_ECDH_RSA_WITH_NULL_SHA | ECDH-RSA-NULL-SHA | [RFC8422] | -+| 0xC00C | TLS_ECDH_RSA_WITH_RC4_128_SHA | ECDH-RSA-RC4-SHA | [RFC8422][RFC6347] | -+| 0xC00D | TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA | ECDH-RSA-DES-CBC3-SHA | [RFC8422] | -+| 0xC00E | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA | ECDH-RSA-AES128-SHA | [RFC8422] | -+| 0xC00F | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA | ECDH-RSA-AES256-SHA | [RFC8422] | -+| 0xC010 | TLS_ECDHE_RSA_WITH_NULL_SHA | ECDHE-RSA-NULL-SHA | [RFC8422] | -+| 0xC011 | TLS_ECDHE_RSA_WITH_RC4_128_SHA | ECDHE-RSA-RC4-SHA | [RFC8422][RFC6347] | -+| 0xC012 | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA | ECDHE-RSA-DES-CBC3-SHA | [RFC8422] | -+| 0xC013 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA | ECDHE-RSA-AES128-SHA | [RFC8422] | -+| 0xC014 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA | ECDHE-RSA-AES256-SHA | [RFC8422] | -+| 0xC015 | TLS_ECDH_anon_WITH_NULL_SHA | AECDH-NULL-SHA | [RFC8422] | -+| 0xC016 | TLS_ECDH_anon_WITH_RC4_128_SHA | AECDH-RC4-SHA | [RFC8422][RFC6347] | -+| 0xC017 | TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA | AECDH-DES-CBC3-SHA | [RFC8422] | -+| 0xC018 | TLS_ECDH_anon_WITH_AES_128_CBC_SHA | AECDH-AES128-SHA | [RFC8422] | -+| 0xC019 | TLS_ECDH_anon_WITH_AES_256_CBC_SHA | AECDH-AES256-SHA | [RFC8422] | -+| 0xC01A | TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA | SRP-3DES-EDE-CBC-SHA | [RFC5054] | -+| 0xC01B | TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA | SRP-RSA-3DES-EDE-CBC-SHA | [RFC5054] | -+| 0xC01C | TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA | SRP-DSS-3DES-EDE-CBC-SHA | [RFC5054] | -+| 0xC01D | TLS_SRP_SHA_WITH_AES_128_CBC_SHA | SRP-AES-128-CBC-SHA | [RFC5054] | -+| 0xC01E | TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA | SRP-RSA-AES-128-CBC-SHA | [RFC5054] | -+| 0xC01F | TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA | SRP-DSS-AES-128-CBC-SHA | [RFC5054] | -+| 0xC020 | TLS_SRP_SHA_WITH_AES_256_CBC_SHA | SRP-AES-256-CBC-SHA | [RFC5054] | -+| 0xC021 | TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA | SRP-RSA-AES-256-CBC-SHA | [RFC5054] | -+| 0xC022 | TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA | SRP-DSS-AES-256-CBC-SHA | [RFC5054] | -+| 0xC023 | TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | ECDHE-ECDSA-AES128-SHA256 | [RFC5289] | -+| 0xC024 | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 | ECDHE-ECDSA-AES256-SHA384 | [RFC5289] | -+| 0xC025 | TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 | ECDH-ECDSA-AES128-SHA256 | [RFC5289] | -+| 0xC026 | TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 | ECDH-ECDSA-AES256-SHA384 | [RFC5289] | -+| 0xC027 | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | ECDHE-RSA-AES128-SHA256 | [RFC5289] | -+| 0xC028 | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 | ECDHE-RSA-AES256-SHA384 | [RFC5289] | -+| 0xC029 | TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 | ECDH-RSA-AES128-SHA256 | [RFC5289] | -+| 0xC02A | TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 | ECDH-RSA-AES256-SHA384 | [RFC5289] | -+| 0xC02B | TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | ECDHE-ECDSA-AES128-GCM-SHA256 | [RFC5289] | -+| 0xC02C | TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 | ECDHE-ECDSA-AES256-GCM-SHA384 | [RFC5289] | -+| 0xC02D | TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 | ECDH-ECDSA-AES128-GCM-SHA256 | [RFC5289] | -+| 0xC02E | TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 | ECDH-ECDSA-AES256-GCM-SHA384 | [RFC5289] | -+| 0xC02F | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | ECDHE-RSA-AES128-GCM-SHA256 | [RFC5289] | -+| 0xC030 | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 | ECDHE-RSA-AES256-GCM-SHA384 | [RFC5289] | -+| 0xC031 | TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 | ECDH-RSA-AES128-GCM-SHA256 | [RFC5289] | -+| 0xC032 | TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 | ECDH-RSA-AES256-GCM-SHA384 | [RFC5289] | -+| 0xC033 | TLS_ECDHE_PSK_WITH_RC4_128_SHA | ECDHE-PSK-RC4-SHA | [RFC5489][RFC6347] | -+| 0xC034 | TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA | ECDHE-PSK-3DES-EDE-CBC-SHA | [RFC5489] | -+| 0xC035 | TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA | ECDHE-PSK-AES128-CBC-SHA | [RFC5489] | -+| 0xC036 | TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA | ECDHE-PSK-AES256-CBC-SHA | [RFC5489] | -+| 0xC037 | TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 | ECDHE-PSK-AES128-CBC-SHA256 | [RFC5489] | -+| 0xC038 | TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 | ECDHE-PSK-AES256-CBC-SHA384 | [RFC5489] | -+| 0xC039 | TLS_ECDHE_PSK_WITH_NULL_SHA | ECDHE-PSK-NULL-SHA | [RFC5489] | -+| 0xC03A | TLS_ECDHE_PSK_WITH_NULL_SHA256 | ECDHE-PSK-NULL-SHA256 | [RFC5489] | -+| 0xC03B | TLS_ECDHE_PSK_WITH_NULL_SHA384 | ECDHE-PSK-NULL-SHA384 | [RFC5489] | -+| 0xC03C | TLS_RSA_WITH_ARIA_128_CBC_SHA256 | ARIA128-SHA256 | [RFC6209] | -+| 0xC03D | TLS_RSA_WITH_ARIA_256_CBC_SHA384 | ARIA256-SHA384 | [RFC6209] | -+| 0xC044 | TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 | DHE-RSA-ARIA128-SHA256 | [RFC6209] | -+| 0xC045 | TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 | DHE-RSA-ARIA256-SHA384 | [RFC6209] | -+| 0xC048 | TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 | ECDHE-ECDSA-ARIA128-SHA256 | [RFC6209] | -+| 0xC049 | TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 | ECDHE-ECDSA-ARIA256-SHA384 | [RFC6209] | -+| 0xC04A | TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 | ECDH-ECDSA-ARIA128-SHA256 | [RFC6209] | -+| 0xC04B | TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 | ECDH-ECDSA-ARIA256-SHA384 | [RFC6209] | -+| 0xC04C | TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 | ECDHE-ARIA128-SHA256 | [RFC6209] | -+| 0xC04D | TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 | ECDHE-ARIA256-SHA384 | [RFC6209] | -+| 0xC04E | TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 | ECDH-ARIA128-SHA256 | [RFC6209] | -+| 0xC04F | TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 | ECDH-ARIA256-SHA384 | [RFC6209] | -+| 0xC050 | TLS_RSA_WITH_ARIA_128_GCM_SHA256 | ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC051 | TLS_RSA_WITH_ARIA_256_GCM_SHA384 | ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC052 | TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 | DHE-RSA-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC053 | TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 | DHE-RSA-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC056 | TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 | DHE-DSS-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC057 | TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 | DHE-DSS-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC05C | TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 | ECDHE-ECDSA-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC05D | TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 | ECDHE-ECDSA-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC05E | TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 | ECDH-ECDSA-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC05F | TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 | ECDH-ECDSA-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC060 | TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 | ECDHE-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC061 | TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 | ECDHE-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC062 | TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 | ECDH-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC063 | TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 | ECDH-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC064 | TLS_PSK_WITH_ARIA_128_CBC_SHA256 | PSK-ARIA128-SHA256 | [RFC6209] | -+| 0xC065 | TLS_PSK_WITH_ARIA_256_CBC_SHA384 | PSK-ARIA256-SHA384 | [RFC6209] | -+| 0xC066 | TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 | DHE-PSK-ARIA128-SHA256 | [RFC6209] | -+| 0xC067 | TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 | DHE-PSK-ARIA256-SHA384 | [RFC6209] | -+| 0xC068 | TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 | RSA-PSK-ARIA128-SHA256 | [RFC6209] | -+| 0xC069 | TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 | RSA-PSK-ARIA256-SHA384 | [RFC6209] | -+| 0xC06A | TLS_PSK_WITH_ARIA_128_GCM_SHA256 | PSK-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC06B | TLS_PSK_WITH_ARIA_256_GCM_SHA384 | PSK-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC06C | TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 | DHE-PSK-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC06D | TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 | DHE-PSK-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC06E | TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 | RSA-PSK-ARIA128-GCM-SHA256 | [RFC6209] | -+| 0xC06F | TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 | RSA-PSK-ARIA256-GCM-SHA384 | [RFC6209] | -+| 0xC070 | TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 | ECDHE-PSK-ARIA128-SHA256 | [RFC6209] | -+| 0xC071 | TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 | ECDHE-PSK-ARIA256-SHA384 | [RFC6209] | -+| 0xC072 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 | ECDHE-ECDSA-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC073 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 | ECDHE-ECDSA-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC074 | TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 | ECDH-ECDSA-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC075 | TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 | ECDH-ECDSA-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC076 | TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 | ECDHE-RSA-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC077 | TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 | ECDHE-RSA-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC078 | TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 | ECDH-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC079 | TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 | ECDH-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC07A | TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 | CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC07B | TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 | CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC07C | TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 | DHE-RSA-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC07D | TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 | DHE-RSA-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC086 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 | ECDHE-ECDSA-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC087 | TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 | ECDHE-ECDSA-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC088 | TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 | ECDH-ECDSA-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC089 | TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 | ECDH-ECDSA-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC08A | TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 | ECDHE-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC08B | TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 | ECDHE-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC08C | TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 | ECDH-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC08D | TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 | ECDH-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC08E | TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 | PSK-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC08F | TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 | PSK-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC090 | TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 | DHE-PSK-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC091 | TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 | DHE-PSK-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC092 | TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 | RSA-PSK-CAMELLIA128-GCM-SHA256 | [RFC6367] | -+| 0xC093 | TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 | RSA-PSK-CAMELLIA256-GCM-SHA384 | [RFC6367] | -+| 0xC094 | TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 | PSK-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC095 | TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 | PSK-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC096 | TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 | DHE-PSK-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC097 | TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 | DHE-PSK-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC098 | TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 | RSA-PSK-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC099 | TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 | RSA-PSK-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC09A | TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 | ECDHE-PSK-CAMELLIA128-SHA256 | [RFC6367] | -+| 0xC09B | TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 | ECDHE-PSK-CAMELLIA256-SHA384 | [RFC6367] | -+| 0xC09C | TLS_RSA_WITH_AES_128_CCM | AES128-CCM | [RFC6655] | -+| 0xC09D | TLS_RSA_WITH_AES_256_CCM | AES256-CCM | [RFC6655] | -+| 0xC09E | TLS_DHE_RSA_WITH_AES_128_CCM | DHE-RSA-AES128-CCM | [RFC6655] | -+| 0xC09F | TLS_DHE_RSA_WITH_AES_256_CCM | DHE-RSA-AES256-CCM | [RFC6655] | -+| 0xC0A0 | TLS_RSA_WITH_AES_128_CCM_8 | AES128-CCM8 | [RFC6655] | -+| 0xC0A1 | TLS_RSA_WITH_AES_256_CCM_8 | AES256-CCM8 | [RFC6655] | -+| 0xC0A2 | TLS_DHE_RSA_WITH_AES_128_CCM_8 | DHE-RSA-AES128-CCM8 | [RFC6655] | -+| 0xC0A3 | TLS_DHE_RSA_WITH_AES_256_CCM_8 | DHE-RSA-AES256-CCM8 | [RFC6655] | -+| 0xC0A4 | TLS_PSK_WITH_AES_128_CCM | PSK-AES128-CCM | [RFC6655] | -+| 0xC0A5 | TLS_PSK_WITH_AES_256_CCM | PSK-AES256-CCM | [RFC6655] | -+| 0xC0A6 | TLS_DHE_PSK_WITH_AES_128_CCM | DHE-PSK-AES128-CCM | [RFC6655] | -+| 0xC0A7 | TLS_DHE_PSK_WITH_AES_256_CCM | DHE-PSK-AES256-CCM | [RFC6655] | -+| 0xC0A8 | TLS_PSK_WITH_AES_128_CCM_8 | PSK-AES128-CCM8 | [RFC6655] | -+| 0xC0A9 | TLS_PSK_WITH_AES_256_CCM_8 | PSK-AES256-CCM8 | [RFC6655] | -+| 0xC0AA | TLS_PSK_DHE_WITH_AES_128_CCM_8 | DHE-PSK-AES128-CCM8 | [RFC6655] | -+| 0xC0AB | TLS_PSK_DHE_WITH_AES_256_CCM_8 | DHE-PSK-AES256-CCM8 | [RFC6655] | -+| 0xC0AC | TLS_ECDHE_ECDSA_WITH_AES_128_CCM | ECDHE-ECDSA-AES128-CCM | [RFC7251] | -+| 0xC0AD | TLS_ECDHE_ECDSA_WITH_AES_256_CCM | ECDHE-ECDSA-AES256-CCM | [RFC7251] | -+| 0xC0AE | TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 | ECDHE-ECDSA-AES128-CCM8 | [RFC7251] | -+| 0xC0AF | TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 | ECDHE-ECDSA-AES256-CCM8 | [RFC7251] | -+| 0xC100 | TLS_GOSTR341112_256_WITH_KUZNYECHIK_CTR_OMAC | GOST2012-KUZNYECHIK-KUZNYECHIKOMAC | [RFC9189] | -+| 0xC101 | TLS_GOSTR341112_256_WITH_MAGMA_CTR_OMAC | GOST2012-MAGMA-MAGMAOMAC | [RFC9189] | -+| 0xC102 | TLS_GOSTR341112_256_WITH_28147_CNT_IMIT | IANA-GOST2012-GOST8912-GOST8912 | [RFC9189] | -+| 0xCC13 | | ECDHE-RSA-CHACHA20-POLY1305-OLD | | -+| 0xCC14 | | ECDHE-ECDSA-CHACHA20-POLY1305-OLD | | -+| 0xCC15 | | DHE-RSA-CHACHA20-POLY1305-OLD | | -+| 0xCCA8 | TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | ECDHE-RSA-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCA9 | TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 | ECDHE-ECDSA-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCAA | TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 | DHE-RSA-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCAB | TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 | PSK-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCAC | TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 | ECDHE-PSK-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCAD | TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 | DHE-PSK-CHACHA20-POLY1305 | [RFC7905] | -+| 0xCCAE | TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 | RSA-PSK-CHACHA20-POLY1305 | [RFC7905] | -+| 0xD001 | TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 | ECDHE-PSK-AES128-GCM-SHA256 | [RFC8442] | -+| 0xE011 | | ECDHE-ECDSA-SM4-CBC-SM3 | | -+| 0xE051 | | ECDHE-ECDSA-SM4-GCM-SM3 | | -+| 0xE052 | | ECDHE-ECDSA-SM4-CCM-SM3 | | -+| 0xFF00 | | GOST-MD5 | | -+| 0xFF01 | | GOST-GOST94 | | -+| 0xFF02 | | GOST-GOST89MAC | | -+| 0xFF03 | | GOST-GOST89STREAM | | -diff --git a/docs/CIPHERS.md b/docs/CIPHERS.md -index 1fb854058..6e899e52d 100644 ---- a/docs/CIPHERS.md -+++ b/docs/CIPHERS.md -@@ -1,427 +1,189 @@ --# Ciphers -+ ++git df curl-8_7_1 > chrome.patch ++mv chrome.patch ../curl-impersonate/chrome/patches/curl-impersonate.patch +diff --git a/include/curl/curl.h b/include/curl/curl.h +index b2377b789..d695b803e 100644 +--- a/include/curl/curl.h ++++ b/include/curl/curl.h +@@ -632,6 +632,7 @@ typedef enum { + CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */ + CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ + CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ ++ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */ + CURL_LAST /* never use! */ + } CURLcode; --(Note these ciphers are set with `CURLOPT_TLS13_CIPHERS` and `--tls13-ciphers`) -+## curl cipher options +@@ -2206,6 +2207,85 @@ typedef enum { + /* millisecond version */ + CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), --`TLS_AES_256_GCM_SHA384` --`TLS_CHACHA20_POLY1305_SHA256` --`TLS_AES_128_GCM_SHA256` --`TLS_AES_128_CCM_8_SHA256` --`TLS_AES_128_CCM_SHA256` -- --## WolfSSL -- --`RC4-SHA`, --`RC4-MD5`, --`DES-CBC3-SHA`, --`AES128-SHA`, --`AES256-SHA`, --`NULL-SHA`, --`NULL-SHA256`, --`DHE-RSA-AES128-SHA`, --`DHE-RSA-AES256-SHA`, --`DHE-PSK-AES256-GCM-SHA384`, --`DHE-PSK-AES128-GCM-SHA256`, --`PSK-AES256-GCM-SHA384`, --`PSK-AES128-GCM-SHA256`, --`DHE-PSK-AES256-CBC-SHA384`, --`DHE-PSK-AES128-CBC-SHA256`, --`PSK-AES256-CBC-SHA384`, --`PSK-AES128-CBC-SHA256`, --`PSK-AES128-CBC-SHA`, --`PSK-AES256-CBC-SHA`, --`DHE-PSK-AES128-CCM`, --`DHE-PSK-AES256-CCM`, --`PSK-AES128-CCM`, --`PSK-AES256-CCM`, --`PSK-AES128-CCM-8`, --`PSK-AES256-CCM-8`, --`DHE-PSK-NULL-SHA384`, --`DHE-PSK-NULL-SHA256`, --`PSK-NULL-SHA384`, --`PSK-NULL-SHA256`, --`PSK-NULL-SHA`, --`HC128-MD5`, --`HC128-SHA`, --`HC128-B2B256`, --`AES128-B2B256`, --`AES256-B2B256`, --`RABBIT-SHA`, --`NTRU-RC4-SHA`, --`NTRU-DES-CBC3-SHA`, --`NTRU-AES128-SHA`, --`NTRU-AES256-SHA`, --`AES128-CCM-8`, --`AES256-CCM-8`, --`ECDHE-ECDSA-AES128-CCM`, --`ECDHE-ECDSA-AES128-CCM-8`, --`ECDHE-ECDSA-AES256-CCM-8`, --`ECDHE-RSA-AES128-SHA`, --`ECDHE-RSA-AES256-SHA`, --`ECDHE-ECDSA-AES128-SHA`, --`ECDHE-ECDSA-AES256-SHA`, --`ECDHE-RSA-RC4-SHA`, --`ECDHE-RSA-DES-CBC3-SHA`, --`ECDHE-ECDSA-RC4-SHA`, --`ECDHE-ECDSA-DES-CBC3-SHA`, --`AES128-SHA256`, --`AES256-SHA256`, --`DHE-RSA-AES128-SHA256`, --`DHE-RSA-AES256-SHA256`, --`ECDH-RSA-AES128-SHA`, --`ECDH-RSA-AES256-SHA`, --`ECDH-ECDSA-AES128-SHA`, --`ECDH-ECDSA-AES256-SHA`, --`ECDH-RSA-RC4-SHA`, --`ECDH-RSA-DES-CBC3-SHA`, --`ECDH-ECDSA-RC4-SHA`, --`ECDH-ECDSA-DES-CBC3-SHA`, --`AES128-GCM-SHA256`, --`AES256-GCM-SHA384`, --`DHE-RSA-AES128-GCM-SHA256`, --`DHE-RSA-AES256-GCM-SHA384`, --`ECDHE-RSA-AES128-GCM-SHA256`, --`ECDHE-RSA-AES256-GCM-SHA384`, --`ECDHE-ECDSA-AES128-GCM-SHA256`, --`ECDHE-ECDSA-AES256-GCM-SHA384`, --`ECDH-RSA-AES128-GCM-SHA256`, --`ECDH-RSA-AES256-GCM-SHA384`, --`ECDH-ECDSA-AES128-GCM-SHA256`, --`ECDH-ECDSA-AES256-GCM-SHA384`, --`CAMELLIA128-SHA`, --`DHE-RSA-CAMELLIA128-SHA`, --`CAMELLIA256-SHA`, --`DHE-RSA-CAMELLIA256-SHA`, --`CAMELLIA128-SHA256`, --`DHE-RSA-CAMELLIA128-SHA256`, --`CAMELLIA256-SHA256`, --`DHE-RSA-CAMELLIA256-SHA256`, --`ECDHE-RSA-AES128-SHA256`, --`ECDHE-ECDSA-AES128-SHA256`, --`ECDH-RSA-AES128-SHA256`, --`ECDH-ECDSA-AES128-SHA256`, --`ECDHE-RSA-AES256-SHA384`, --`ECDHE-ECDSA-AES256-SHA384`, --`ECDH-RSA-AES256-SHA384`, --`ECDH-ECDSA-AES256-SHA384`, --`ECDHE-RSA-CHACHA20-POLY1305`, --`ECDHE-ECDSA-CHACHA20-POLY1305`, --`DHE-RSA-CHACHA20-POLY1305`, --`ECDHE-RSA-CHACHA20-POLY1305-OLD`, --`ECDHE-ECDSA-CHACHA20-POLY1305-OLD`, --`DHE-RSA-CHACHA20-POLY1305-OLD`, --`ADH-AES128-SHA`, --`QSH`, --`RENEGOTIATION-INFO`, --`IDEA-CBC-SHA`, --`ECDHE-ECDSA-NULL-SHA`, --`ECDHE-PSK-NULL-SHA256`, --`ECDHE-PSK-AES128-CBC-SHA256`, --`PSK-CHACHA20-POLY1305`, --`ECDHE-PSK-CHACHA20-POLY1305`, --`DHE-PSK-CHACHA20-POLY1305`, --`EDH-RSA-DES-CBC3-SHA`, -- --## Schannel -- --Schannel allows the enabling and disabling of encryption algorithms, but not --specific cipher suites, prior to TLS 1.3. The algorithms are --[defined](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) by --Microsoft. -- --The algorithms below are for TLS 1.2 and earlier. TLS 1.3 is covered in the --next section. -- --There is also the case that the selected algorithm is not supported by the --protocol or does not match the ciphers offered by the server during the SSL --negotiation. In this case curl returns error --`CURLE_SSL_CONNECT_ERROR (35) SEC_E_ALGORITHM_MISMATCH` --and the request fails. -- --`CALG_MD2`, --`CALG_MD4`, --`CALG_MD5`, --`CALG_SHA`, --`CALG_SHA1`, --`CALG_MAC`, --`CALG_RSA_SIGN`, --`CALG_DSS_SIGN`, --`CALG_NO_SIGN`, --`CALG_RSA_KEYX`, --`CALG_DES`, --`CALG_3DES_112`, --`CALG_3DES`, --`CALG_DESX`, --`CALG_RC2`, --`CALG_RC4`, --`CALG_SEAL`, --`CALG_DH_SF`, --`CALG_DH_EPHEM`, --`CALG_AGREEDKEY_ANY`, --`CALG_HUGHES_MD5`, --`CALG_SKIPJACK`, --`CALG_TEK`, --`CALG_CYLINK_MEK`, --`CALG_SSL3_SHAMD5`, --`CALG_SSL3_MASTER`, --`CALG_SCHANNEL_MASTER_HASH`, --`CALG_SCHANNEL_MAC_KEY`, --`CALG_SCHANNEL_ENC_KEY`, --`CALG_PCT1_MASTER`, --`CALG_SSL2_MASTER`, --`CALG_TLS1_MASTER`, --`CALG_RC5`, --`CALG_HMAC`, --`CALG_TLS1PRF`, --`CALG_HASH_REPLACE_OWF`, --`CALG_AES_128`, --`CALG_AES_192`, --`CALG_AES_256`, --`CALG_AES`, --`CALG_SHA_256`, --`CALG_SHA_384`, --`CALG_SHA_512`, --`CALG_ECDH`, --`CALG_ECMQV`, --`CALG_ECDSA`, --`CALG_ECDH_EPHEM`, -- --As of curl 7.77.0, you can also pass `SCH_USE_STRONG_CRYPTO` as a cipher name --to [constrain the set of available ciphers as specified in the Schannel --documentation](https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022). --Note that the supported ciphers in this case follow the OS version, so if you --are running an outdated OS you might still be supporting weak ciphers. -- --### TLS 1.3 cipher suites -- --You can set TLS 1.3 ciphers for Schannel by using `CURLOPT_TLS13_CIPHERS` or --`--tls13-ciphers` with the names below. -- --If TLS 1.3 cipher suites are set then libcurl adds or restricts Schannel TLS --1.3 algorithms automatically. Essentially, libcurl is emulating support for --individual TLS 1.3 cipher suites since Schannel does not support it directly. -- --`TLS_AES_256_GCM_SHA384` --`TLS_AES_128_GCM_SHA256` --`TLS_CHACHA20_POLY1305_SHA256` --`TLS_AES_128_CCM_8_SHA256` --`TLS_AES_128_CCM_SHA256` -- --Note if you set TLS 1.3 ciphers without also setting the minimum TLS version --to 1.3 then it is possible Schannel may negotiate an earlier TLS version and --cipher suite if your libcurl and OS settings allow it. You can set the minimum --TLS version by using `CURLOPT_SSLVERSION` or `--tlsv1.3`. -- --## BearSSL -- --BearSSL ciphers can be specified by either the OpenSSL name (`ECDHE-RSA-AES128-GCM-SHA256`) or the IANA name (`TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`). -- --Since BearSSL 0.1: -- --`DES-CBC3-SHA` --`AES128-SHA` --`AES256-SHA` --`AES128-SHA256` --`AES256-SHA256` --`AES128-GCM-SHA256` --`AES256-GCM-SHA384` --`ECDH-ECDSA-DES-CBC3-SHA` --`ECDH-ECDSA-AES128-SHA` --`ECDH-ECDSA-AES256-SHA` --`ECDHE-ECDSA-DES-CBC3-SHA` --`ECDHE-ECDSA-AES128-SHA` --`ECDHE-ECDSA-AES256-SHA` --`ECDH-RSA-DES-CBC3-SHA` --`ECDH-RSA-AES128-SHA` --`ECDH-RSA-AES256-SHA` --`ECDHE-RSA-DES-CBC3-SHA` --`ECDHE-RSA-AES128-SHA` --`ECDHE-RSA-AES256-SHA` --`ECDHE-ECDSA-AES128-SHA256` --`ECDHE-ECDSA-AES256-SHA384` --`ECDH-ECDSA-AES128-SHA256` --`ECDH-ECDSA-AES256-SHA384` --`ECDHE-RSA-AES128-SHA256` --`ECDHE-RSA-AES256-SHA384` --`ECDH-RSA-AES128-SHA256` --`ECDH-RSA-AES256-SHA384` --`ECDHE-ECDSA-AES128-GCM-SHA256` --`ECDHE-ECDSA-AES256-GCM-SHA384` --`ECDH-ECDSA-AES128-GCM-SHA256` --`ECDH-ECDSA-AES256-GCM-SHA384` --`ECDHE-RSA-AES128-GCM-SHA256` --`ECDHE-RSA-AES256-GCM-SHA384` --`ECDH-RSA-AES128-GCM-SHA256` --`ECDH-RSA-AES256-GCM-SHA384` -- --Since BearSSL 0.2: -- --`ECDHE-RSA-CHACHA20-POLY1305` --`ECDHE-ECDSA-CHACHA20-POLY1305` -- --Since BearSSL 0.6: -- --`AES128-CCM` --`AES256-CCM` --`AES128-CCM8` --`AES256-CCM8` --`ECDHE-ECDSA-AES128-CCM` --`ECDHE-ECDSA-AES256-CCM` --`ECDHE-ECDSA-AES128-CCM8` --`ECDHE-ECDSA-AES256-CCM8` -+With curl's option -+[`--tls13-ciphers`](https://curl.se/docs/manpage.html#--tls13-ciphers) -+or -+[`CURLOPT_TLS13_CIPHERS`](https://curl.se/libcurl/c/CURLOPT_TLS13_CIPHERS.html) -+users can control which cipher suites to consider when negotiating TLS 1.3 -+connections. With option -+[`--ciphers`](https://curl.se/docs/manpage.html#--ciphers) -+or -+[`CURLOPT_SSL_CIPHER_LIST`](https://curl.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html) -+users can control which cipher suites to consider when negotiating -+TLS 1.2 (1.1, 1.0) connections. -+ -+By default, curl may negotiate TLS 1.3 and TLS 1.2 connections, so the cipher -+suites considered when negotiating a TLS connection are a union of the TLS 1.3 -+and TLS 1.2 cipher suites. If you want curl to consider only TLS 1.3 cipher -+suites for the connection, you have to set the minimum TLS version to 1.3 by -+using [`--tlsv1.3`](https://curl.se/docs/manpage.html#--tlsv13) -+or [`CURLOPT_SSLVERSION`](https://curl.se/libcurl/c/CURLOPT_SSLVERSION.html) -+with `CURL_SSLVERSION_TLSv1_3`. -+ -+Both the TLS 1.3 and TLS 1.2 cipher options expect a list of cipher suites -+separated by colons (`:`). This list is parsed opportunistically, cipher suites -+that are not recognized or implemented are ignored. As long as there is at -+least one recognized cipher suite in the list, the list is considered valid. -+ -+For both the TLS 1.3 and TLS 1.2 cipher options, the order in which the -+cipher suites are specified determine the preference of them. When negotiating -+a TLS connection the server picks a cipher suite from the intersection of the -+cipher suites supported by the server and the cipher suites sent by curl. If -+the server is configured to honor the client's cipher preference, the first -+common cipher suite in the list sent by curl is chosen. -+ -+## TLS 1.3 cipher suites -+ -+Setting TLS 1.3 cipher suites is supported by curl with -+OpenSSL (1.1.1+, curl 7.61.0+), LibreSSL (3.4.1+, curl 8.3.0+), -+wolfSSL (curl 8.10.0+), mbedTLS (3.6.0+, curl 8.10.0+) and -+Schannel (curl 7.85.0+). -+ -+The list of cipher suites that can be used for the `--tls13-ciphers` option: -+``` -+TLS_AES_128_GCM_SHA256 -+TLS_AES_256_GCM_SHA384 -+TLS_CHACHA20_POLY1305_SHA256 -+TLS_AES_128_CCM_SHA256 -+TLS_AES_128_CCM_8_SHA256 -+``` -+ -+### wolfSSL notes -+ -+In addition to above list the following cipher suites can be used: -+`TLS_SM4_GCM_SM3` `TLS_SM4_CCM_SM3` `TLS_SHA256_SHA256` `TLS_SHA384_SHA384`. -+Usage of these cipher suites is not recommended. (The last two cipher suites -+are NULL ciphers, offering no encryption whatsoever.) -+ -+### Schannel notes -+ -+Schannel does not support setting individual TLS 1.3 cipher suites directly. -+To support `--tls13-ciphers` curl emulates it by adding or restricting -+algorithms to use. Due to this the specified order of preference of the -+cipher suites is not taken into account. -+ -+## TLS 1.2 (1.1, 1.0) cipher suites -+ -+Setting TLS 1.2 cipher suites is supported by curl with OpenSSL, LibreSSL, -+BoringSSL, mbedTLS (curl 8.8.0+), wolfSSL (curl 7.53.0+), -+Secure Transport (curl 7.77.0+) and BearSSL (curl 7.83.0+). Schannel does not -+support setting cipher suites directly, but does support setting algorithms -+(curl 7.61.0+), see Schannel notes below. -+ -+For TLS 1.2 cipher suites there are multiple naming schemes, the two most used -+are with OpenSSL names (e.g. `ECDHE-RSA-AES128-GCM-SHA256`) and IANA names -+(e.g. `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`). IANA names of TLS 1.2 cipher -+suites look similar to TLS 1.3 cipher suite names, to distinguish them note -+that TLS 1.2 names contain `_WITH_`, while TLS 1.3 names do not. When setting -+TLS 1.2 cipher suites with curl it is recommended that you use OpenSSL names -+as these are most widely recognized by the supported SSL backends. -+ -+The complete list of cipher suites that may be considered for the `--ciphers` -+option is extensive, it consists of more than 300 ciphers suites. However, -+nowadays for most of them their usage is discouraged, and support for a lot of -+them have been removed from the various SSL backends, if ever implemented at -+all. ++ /* curl-impersonate: A list of headers used by the impersonated browser. ++ * If given, merged with CURLOPT_HTTPHEADER. */ ++ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 1000), + -+A shortened list (based on [recommendations by -+Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS)) of cipher suites, -+which are (mostly) supported by all SSL backends, that can be used for the -+`--ciphers` option: -+``` -+ECDHE-ECDSA-AES128-GCM-SHA256 -+ECDHE-RSA-AES128-GCM-SHA256 -+ECDHE-ECDSA-AES256-GCM-SHA384 -+ECDHE-RSA-AES256-GCM-SHA384 -+ECDHE-ECDSA-CHACHA20-POLY1305 -+ECDHE-RSA-CHACHA20-POLY1305 -+DHE-RSA-AES128-GCM-SHA256 -+DHE-RSA-AES256-GCM-SHA384 -+DHE-RSA-CHACHA20-POLY1305 -+ECDHE-ECDSA-AES128-SHA256 -+ECDHE-RSA-AES128-SHA256 -+ECDHE-ECDSA-AES128-SHA -+ECDHE-RSA-AES128-SHA -+ECDHE-ECDSA-AES256-SHA384 -+ECDHE-RSA-AES256-SHA384 -+ECDHE-ECDSA-AES256-SHA -+ECDHE-RSA-AES256-SHA -+DHE-RSA-AES128-SHA256 -+DHE-RSA-AES256-SHA256 -+AES128-GCM-SHA256 -+AES256-GCM-SHA384 -+AES128-SHA256 -+AES256-SHA256 -+AES128-SHA -+AES256-SHA -+DES-CBC3-SHA -+``` ++ /* curl-impersonate: A list of TLS signature hash algorithms. ++ * See https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1 */ ++ CURLOPT(CURLOPT_SSL_SIG_HASH_ALGS, CURLOPTTYPE_STRINGPOINT, 1001), + -+See this [list](https://github.com/curl/curl/blob/master/docs/CIPHERS-TLS12.md) -+for a complete list of TLS 1.2 cipher suites. ++ /* curl-impersonate: Whether to enable ALPS in TLS or not. ++ * See https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps. ++ * Support for ALPS is minimal and is intended only for the TLS client ++ * hello to match. */ ++ CURLOPT(CURLOPT_SSL_ENABLE_ALPS, CURLOPTTYPE_LONG, 1002), + -+### OpenSSL notes ++ /* curl-impersonate: Comma-separated list of certificate compression ++ * algorithms to use. These are published in the client hello. ++ * Supported algorithms are "zlib" and "brotli". ++ * See https://datatracker.ietf.org/doc/html/rfc8879 */ ++ CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 1003), + -+In addition to specifying a list of cipher suites, OpenSSL also accepts a -+format with specific cipher strings (like `TLSv1.2`, `AESGCM`, `CHACHA20`) and -+`!`, `-` and `+` operators. Refer to the -+[OpenSSL cipher documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-list-format) -+for further information on that format. ++ /* Enable/disable TLS session ticket extension (RFC5077) */ ++ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 1004), + -+### Schannel notes ++ /* ++ * curl-impersonate: ++ * Set the order of the HTTP/2 pseudo headers. The value must contain ++ * the letters 'm', 'a', 's', 'p' representing the pseudo-headers ++ * ":method", ":authority", ":scheme", ":path" in the desired order of ++ * appearance in the HTTP/2 HEADERS frame. ++ */ ++ CURLOPT(CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPTTYPE_STRINGPOINT, 1005), + -+Schannel does not support setting individual TLS 1.2 cipher suites directly. -+It only allows the enabling and disabling of encryption algorithms. These are -+in the form of `CALG_xxx`, see the [Schannel `ALG_ID` -+documentation](https://docs.microsoft.com/windows/desktop/SecCrypto/alg-id) -+for a list of these algorithms. Also, (since curl 7.77.0) -+`SCH_USE_STRONG_CRYPTO` can be given to pass that flag to Schannel, lookup the -+[documentation for the Windows version in -+use](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) -+to see how that affects the cipher suite selection. When not specifying the -+`--chiphers` and `--tl13-ciphers` options curl passes this flag by default. ++ /* ++ * curl-impersonate: ++ * HTTP2 settings frame keys and values, format: 1:v;2:v;3:v ++ */ ++ CURLOPT(CURLOPT_HTTP2_SETTINGS, CURLOPTTYPE_STRINGPOINT, 1006), + -+## Examples ++ /* ++ * curl-impersonate: Whether to enable Boringssl permute extensions ++ * See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_permute_extensions. ++ */ ++ CURLOPT(CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOPTTYPE_LONG, 1007), + -+```sh -+curl \ -+ --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \ -+ --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ -+ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \ -+ https://example.com/ -+``` -+Restrict ciphers to `aes128-gcm` and `chacha20`. Works with OpenSSL, LibreSSL, -+mbedTLS and wolfSSL. ++ /* ++ * curl-impersonate: ++ * HTTP2 initial window update ++ */ ++ CURLOPT(CURLOPT_HTTP2_WINDOW_UPDATE, CURLOPTTYPE_LONG, 1008), + -+```sh -+curl \ -+ --tlsv1.3 \ -+ --tls13-ciphers TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256 \ -+ https://example.com/ -+``` -+Restrict to only TLS 1.3 with `aes128-gcm` and `chacha20` ciphers. Works with -+OpenSSL, LibreSSL, mbedTLS, wolfSSL and Schannel. ++ /* curl-impersonate: ++ * set ECH configuration ++ */ ++ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 1009), + -+```sh -+curl \ -+ --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ -+ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305 \ -+ https://example.com/ -+``` -+Restrict TLS 1.2 ciphers to `aes128-gcm` and `chacha20`, use default TLS 1.3 -+ciphers (if TLS 1.3 is available). Works with OpenSSL, LibreSSL, BoringSSL, -+mbedTLS, wolfSSL, Secure Transport and BearSSL. ++ /* ++ * curl-impersonate: ++ * Set the initial streams settings for http2. ++ */ ++ CURLOPT(CURLOPT_HTTP2_STREAMS, CURLOPTTYPE_STRINGPOINT, 1010), + -+## Further reading -+- [OpenSSL cipher suite names documentation](https://docs.openssl.org/master/man1/openssl-ciphers/#cipher-suite-names) -+- [wolfSSL cipher support documentation](https://www.wolfssl.com/documentation/manuals/wolfssl/chapter04.html#cipher-support) -+- [mbedTLS cipher suites reference](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/ssl__ciphersuites_8h/) -+- [Schannel cipher suites documentation](https://learn.microsoft.com/en-us/windows/win32/secauthn/cipher-suites-in-schannel) -+- [BearSSL supported crypto](https://www.bearssl.org/support.html) -+- [Secure Transport cipher suite values](https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values) -+- [IANA cipher suites list](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4) -+- [Wikipedia cipher suite article](https://en.wikipedia.org/wiki/Cipher_suite) -diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt -index 9c0b37691..8a5c87f95 100644 ---- a/docs/CMakeLists.txt -+++ b/docs/CMakeLists.txt -@@ -21,10 +21,26 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --#add_subdirectory(examples) ++ /* curl-impersonate: enable tls grease */ ++ CURLOPT(CURLOPT_TLS_GREASE, CURLOPTTYPE_LONG, 1011), + - if(BUILD_LIBCURL_DOCS) - add_subdirectory(libcurl) - endif() - if(ENABLE_CURL_MANUAL AND BUILD_CURL_EXE) - add_subdirectory(cmdline-opts) - endif() ++ /* curl-impersonate: set tls extension order */ ++ CURLOPT(CURLOPT_TLS_EXTENSION_ORDER, CURLOPTTYPE_STRINGPOINT, 1012), + -+if(BUILD_MISC_DOCS) -+ foreach(_man_misc IN ITEMS "curl-config" "mk-ca-bundle") -+ set(_man_target "${CMAKE_CURRENT_BINARY_DIR}/${_man_misc}.1") -+ add_custom_command(OUTPUT "${_man_target}" -+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -+ COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/cd2nroff" "${_man_misc}.md" > "${_man_target}" -+ DEPENDS "${_man_misc}.md" -+ VERBATIM -+ ) -+ add_custom_target("curl-generate-${_man_misc}.1" ALL DEPENDS "${_man_target}") -+ if(NOT CURL_DISABLE_INSTALL) -+ install(FILES "${_man_target}" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") -+ endif() -+ endforeach() -+endif() -diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md -index 1f71c387b..5c8878189 100644 ---- a/docs/CODE_OF_CONDUCT.md -+++ b/docs/CODE_OF_CONDUCT.md -@@ -1,3 +1,9 @@ -+ ++ /* curl-impersonate: enable tls key usage check, defaults: on */ ++ CURLOPT(CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOPTTYPE_LONG, 1014), + - Contributor Code of Conduct - =========================== - -diff --git a/docs/CODE_REVIEW.md b/docs/CODE_REVIEW.md -index 0776d30a0..bee26a3f3 100644 ---- a/docs/CODE_REVIEW.md -+++ b/docs/CODE_REVIEW.md -@@ -1,3 +1,9 @@ -+ ++ /* curl-impersonate: enable tls status request */ ++ CURLOPT(CURLOPT_TLS_STATUS_REQUEST, CURLOPTTYPE_LONG, 1016), + - # How to do code reviews for curl - - Anyone and everyone is encouraged and welcome to review code submissions in -@@ -135,13 +141,13 @@ data. Where it comes from and where it goes. - `size_t` is not a fixed size. `time_t` can be signed or unsigned and have - different sizes. Relying on variable sizes is a red flag. + CURLOPT_LASTENTRY /* the last unused */ + } CURLoption; --Also remember that endianness and >= 32 bit accesses to unaligned addresses -+Also remember that endianness and >= 32-bit accesses to unaligned addresses - are problematic areas. +diff --git a/include/curl/easy.h b/include/curl/easy.h +index 1285101c5..c620065dc 100644 +--- a/include/curl/easy.h ++++ b/include/curl/easy.h +@@ -43,6 +43,16 @@ CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); + CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); + CURL_EXTERN void curl_easy_cleanup(CURL *curl); - ## Integer overflows ++/* ++ * curl-impersonate: Tell libcurl to impersonate a browser. ++ * This is a wrapper function that calls curl_easy_setopt() ++ * multiple times with all the parameters required. That's also why it was ++ * created as a separate API function and not just as another option to ++ * curl_easy_setopt(). ++ */ ++CURL_EXTERN CURLcode curl_easy_impersonate(CURL *curl, const char *target, ++ int default_headers); ++ + /* + * NAME curl_easy_getinfo() + * +diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h +index b880f3dc6..79074e011 100644 +--- a/include/curl/typecheck-gcc.h ++++ b/include/curl/typecheck-gcc.h +@@ -275,6 +275,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DOH_URL || \ ++ (option) == CURLOPT_ECH || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 1237c8e99..6b2961018 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -31,7 +31,7 @@ EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ + config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ + Makefile.soname --Be careful about integer overflows. Some variable types can be either 32 bit --or 64 bit. Integer overflows must be detected and acted on *before* they -+Be careful about integer overflows. Some variable types can be either 32-bit -+or 64-bit. Integer overflows must be detected and acted on *before* they - happen. +-lib_LTLIBRARIES = libcurl.la ++lib_LTLIBRARIES = libcurl-impersonate-chrome.la - ## Dangerous use of functions -diff --git a/docs/CONTRIBUTE.md b/docs/CONTRIBUTE.md -index 6288dac90..8860f87c6 100644 ---- a/docs/CONTRIBUTE.md -+++ b/docs/CONTRIBUTE.md -@@ -1,3 +1,9 @@ -+ -+ - # Contributing to the curl project + if BUILD_UNITTESTS + noinst_LTLIBRARIES = libcurlu.la +@@ -67,51 +67,51 @@ AM_CFLAGS = + # Makefile.inc provides the CSOURCES and HHEADERS defines + include Makefile.inc - This document is intended to offer guidelines on how to best contribute to the -@@ -18,7 +24,7 @@ Before posting to one of the curl mailing lists, please read up on the - We also hang out on IRC in #curl on libera.chat +-libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) ++libcurl_impersonate_chrome_la_SOURCES = $(CSOURCES) $(HHEADERS) + libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) - If you are at all interested in the code side of things, consider clicking --'watch' on the [curl repo on GitHub](https://github.com/curl/curl) to be -+'watch' on the [curl repository on GitHub](https://github.com/curl/curl) to be - notified of pull requests and new issues posted there. +-libcurl_la_CPPFLAGS_EXTRA = +-libcurl_la_LDFLAGS_EXTRA = +-libcurl_la_CFLAGS_EXTRA = ++libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA = ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA = ++libcurl_impersonate_chrome_la_CFLAGS_EXTRA = - ## License and copyright -@@ -77,11 +83,11 @@ fix one bug at a time and send them as separate patches. + if CURL_LT_SHLIB_USE_VERSION_INFO +-libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += $(VERSIONINFO) + endif - ### Write Separate Changes + if CURL_LT_SHLIB_USE_NO_UNDEFINED +-libcurl_la_LDFLAGS_EXTRA += -no-undefined ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -no-undefined + endif --It is annoying when you get a huge patch from someone that is said to fix 511 --odd problems, but discussions and opinions do not agree with 510 of them - or --509 of them were already fixed in a different way. Then the person merging --this change needs to extract the single interesting patch from somewhere --within the huge pile of source, and that creates a lot of extra work. -+It is annoying when you get a huge patch from someone that is said to fix 11 -+odd problems, but discussions and opinions do not agree with 10 of them - or 9 -+of them were already fixed in a different way. Then the person merging this -+change needs to extract the single interesting patch from somewhere within the -+huge pile of source, and that creates a lot of extra work. + if CURL_LT_SHLIB_USE_MIMPURE_TEXT +-libcurl_la_LDFLAGS_EXTRA += -mimpure-text ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -mimpure-text + endif - Preferably, each fix that corrects a problem should be in its own patch/commit - with its own description/commit message stating exactly what they correct so -@@ -123,9 +129,9 @@ If you do not have test cases or perhaps you have done something that is hard - to write tests for, do explain exactly how you have otherwise tested and - verified your changes. + if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS +-libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers + else + # if symbol-hiding is enabled, hide them! + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' ++libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' + endif + endif --## Submit Your Changes -+# Submit Your Changes + if USE_CPPFLAG_CURL_STATICLIB +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB ++libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB + else + if HAVE_WINDRES +-libcurl_la_SOURCES += $(LIB_RCFILES) ++libcurl_impersonate_chrome_la_SOURCES += $(LIB_RCFILES) + $(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h + endif + endif --### How to get your changes into the main sources -+## Get your changes merged + if DOING_CURL_SYMBOL_HIDING +-libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS +-libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) ++libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS ++libcurl_impersonate_chrome_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) + endif - Ideally you file a [pull request on - GitHub](https://github.com/curl/curl/pulls), but you can also send your plain -@@ -147,7 +153,7 @@ fix nits/flaws. This is important. We take lack of replies as a sign that you - are not anxious to get your patch accepted and we tend to simply drop such - changes. +-libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) +-libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) +-libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) ++libcurl_impersonate_chrome_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA) ++libcurl_impersonate_chrome_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_impersonate_chrome_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) ++libcurl_impersonate_chrome_la_CFLAGS = $(AM_CFLAGS) $(libcurl_impersonate_chrome_la_CFLAGS_EXTRA) --### About pull requests -+## About pull requests + libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS + libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) +diff --git a/lib/Makefile.inc b/lib/Makefile.inc +index 400e2b1ac..ff3e479aa 100644 +--- a/lib/Makefile.inc ++++ b/lib/Makefile.inc +@@ -177,6 +177,7 @@ LIB_CFILES = \ + idn.c \ + if2ip.c \ + imap.c \ ++ impersonate.c \ + inet_ntop.c \ + inet_pton.c \ + krb5.c \ +diff --git a/lib/content_encoding.c b/lib/content_encoding.c +index c1abf24e8..8e926dd2e 100644 +--- a/lib/content_encoding.c ++++ b/lib/content_encoding.c +@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data, + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ - With GitHub it is easy to send a [pull - request](https://github.com/curl/curl/pulls) to the curl project to have -@@ -179,7 +185,23 @@ checks and qualifications this pull request must also receive more "votes" of - user support. More signs that people want this to happen. It could be in the - form of messages saying so, or thumbs-up reactions on GitHub. +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); --### Making quality changes -+## When the pull request is approved -+ -+If it does not seem to get approved when you think it is ready - feel free to -+ask for approval. -+ -+Once your pull request has been approved it can be merged by a maintainer. -+ -+For new features, or changes, we require that the *feature window* is open for -+the pull request to be merged. This is typically a three week period that -+starts ten days after a previous release. New features submitted as pull -+requests while the window is closed simply have to wait until it opens to get -+merged. -+ -+If time passes without your approved pull request gets merged: feel free to -+ask what more you can do to make it happen. -+ -+## Making quality changes - - Make the patch against as recent source versions as possible. - -@@ -187,48 +209,22 @@ If you have followed the tips in this document and your patch still has not - been incorporated or responded to after some weeks, consider resubmitting it - to the list or better yet: change it to a pull request. - --### Commit messages -+## Commit messages - --A short guide to how to write git commit messages in the curl project. -+How to write git commit messages in the curl project. - - ---- start ---- - [area]: [short line describing the main effect] - -- empty line -- - [full description, no wider than 72 columns that describes as much as - possible as to why this change is made, and possibly what things -- it fixes and everything else that is related, with unwieldy URLs replaced -- with references like [0], [1], etc.] -- -- empty line -- -- [[0] URL - Reference to a URL in the description, almost like Markdown; -- the last numbered reference is followed by an -- empty line -- ] -- [Follow-up to {shorthash} - if this fixes or continues a previous commit; -- add a Ref: that commit's PR or issue if it's not a small, obvious fix; -- followed by an -- empty line -- ] -- [Bug: URL to the source of the report or more related discussion; use Fixes -- for GitHub issues instead when that is appropriate] -- [Approved-by: John Doe - credit someone who approved the PR; if you are -- committing this for someone else using --author=... you do not need this -- as you are implicitly approving it by committing] -- [Authored-by: John Doe - credit the original author of the code; only use -- this if you cannot use "git commit --author=..."] -- [Signed-off-by: John Doe - we do not use this, but do not bother removing it] -- [whatever-else-by: credit all helpers, finders, doers; try to use one of -- the following keywords if at all possible, for consistency: -- Acked-by:, Assisted-by:, Co-authored-by:, Found-by:, Reported-by:, -- Reviewed-by:, Suggested-by:, Tested-by:] -- [Ref: #1234 - if this is related to a GitHub issue or PR, possibly one that -- has already been closed] -- [Ref: URL to more information about the commit; use Bug: instead for -- a reference to a bug on another bug tracker] -- [Fixes #1234 - if this closes a GitHub issue; GitHub closes the issue once -- this commit is merged] -- [Closes #1234 - if this closes a GitHub PR; GitHub closes the PR once this -- commit is merged] -- ---- stop ---- -- --The first line is a succinct description of the change: -- -- - use the imperative, present tense: "change" not "changed" nor "changes" -+ it fixes and everything else that is related, -+ -- end -- -+ -+The first line is a succinct description of the change and should ideally work -+as a single line in the RELEASE NOTES. -+ -+ - use the imperative, present tense: **change** not "changed" nor "changes" - - do not capitalize the first letter - - no period (.) at the end - -@@ -236,72 +232,66 @@ The `[area]` in the first line can be `http2`, `cookies`, `openssl` or - similar. There is no fixed list to select from but using the same "area" as - other related changes could make sense. - --Do not forget to use commit --author=... if you commit someone else's work, and --make sure that you have your own user and email setup correctly in git before --you commit. -+## Commit message keywords - --Add whichever header lines as appropriate, with one line per person if more --than one person was involved. There is no need to credit yourself unless you --are using --author=... which hides your identity. Do not include people's --email addresses in headers to avoid spam, unless they are already public from --a previous commit; saying `{userid} on github` is OK. -+Use the following ways to improve the message and provide pointers to related -+work. - --### Write Access to git Repository -+- `Follow-up to {shorthash}` - if this fixes or continues a previous commit; -+add a `Ref:` that commit's PR or issue if it is not a small, obvious fix; -+followed by an empty line - --If you are a frequent contributor, you may be given push access to the git --repository and then you are able to push your changes straight into the git --repo instead of sending changes as pull requests or by mail as patches. -+- `Bug: URL` to the source of the report or more related discussion; use -+`Fixes` for GitHub issues instead when that is appropriate. - --Just ask if this is what you would want. You are required to have posted --several high quality patches first, before you can be granted push access. -- --### How To Make a Patch with git -- --You need to first checkout the repository: -- -- git clone https://github.com/curl/curl.git -- --You then proceed and edit all the files you like and you commit them to your --local repository: -- -- git commit [file] -+- `Approved-by: John Doe` - credit someone who approved the PR. - --As usual, group your commits so that you commit all changes at once that --constitute a logical change. -+- `Authored-by: John Doe` - credit the original author of the code; only use -+this if you cannot use `git commit --author=...`. - --Once you have done all your commits and you are happy with what you see, you --can make patches out of your changes that are suitable for mailing: -+- `Signed-off-by: John Doe` - we do not use this, but do not bother removing -+ it. - -- git format-patch remotes/origin/master -+- `whatever-else-by:` credit all helpers, finders, doers; try to use one of -+the following keywords if at all possible, for consistency: `Acked-by:`, -+`Assisted-by:`, `Co-authored-by:`, `Found-by:`, `Reported-by:`, -+`Reviewed-by:`, `Suggested-by:`, `Tested-by:`. - --This creates files in your local directory named `NNNN-[name].patch` for each --commit. -+- `Ref: #1234` - if this is related to a GitHub issue or PR, possibly one that -+has already been closed. - --Now send those patches off to the curl-library list. You can of course opt to --do that with the 'git send-email' command. -+- `Ref: URL` to more information about the commit; use `Bug:` instead for a -+reference to a bug on another bug tracker] - --### How To Make a Patch without git -+- `Fixes #1234` - if this fixes a GitHub issue; GitHub closes the issue once -+this commit is merged. - --Keep a copy of the unmodified curl sources. Make your changes in a separate --source tree. When you think you have something that you want to offer the --curl community, use GNU diff to generate patches. -+- `Closes #1234` - if this merges a GitHub PR; GitHub closes the PR once this -+commit is merged. - --If you have modified a single file, try something like: -+Do not forget to use commit with `--author` if you commit someone else's work, -+and make sure that you have your own user and email setup correctly in git -+before you commit. + /* Set the compressed input when this function is called */ +@@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data, + struct zlib_writer *zp = (struct zlib_writer *) writer; + z_stream *z = &zp->z; /* zlib state structure */ -- diff -u unmodified-file.c my-changed-one.c > my-fixes.diff -+Add whichever header lines as appropriate, with one line per person if more -+than one person was involved. There is no need to credit yourself unless you -+are using `--author` which hides your identity. Do not include people's email -+addresses in headers to avoid spam, unless they are already public from a -+previous commit; saying `{userid} on github` is OK. +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); --If you have modified several files, possibly in different directories, you --can use diff recursively: -+## Push Access + if(zp->zlib_init == ZLIB_INIT_GZIP) { +@@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data, + CURLcode result = CURLE_OK; + BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; -- diff -ur curl-original-dir curl-modified-sources-dir > my-fixes.diff -+If you are a frequent contributor, you may be given push access to the git -+repository and then you are able to push your changes straight into the git -+repository instead of sending changes as pull requests or by mail as patches. +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); --The GNU diff and GNU patch tools exist for virtually all platforms, including --all kinds of Unixes and Windows. -+Just ask if this is what you would want. You are required to have posted -+several high quality patches first, before you can be granted push access. + if(!bp->br) +@@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data, + ZSTD_outBuffer out; + size_t errorCode; --### Useful resources -+## Useful resources - - [Webinar on getting code into cURL](https://www.youtube.com/watch?v=QmZ3W1d6LQI) +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); --## Update copyright and license information -+# Update copyright and license information + if(!zp->decomp) { +@@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data, + (void) buf; + (void) nbytes; - There is a CI job called **REUSE compliance / check** that runs on every pull - request and commit to verify that the *REUSE state* of all files are still -@@ -309,9 +299,9 @@ fine. +- if(!(type & CLIENTWRITE_BODY)) ++ if(!(type & CLIENTWRITE_BODY) || !nbytes) + return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - This means that all files need to have their license and copyright information - clearly stated. Ideally by having the standard curl source code header, with --the SPDX-License-Identifier included. If the header does not work, you can use a --smaller header or add the information for a specific file to the `.reuse/dep5` --file. -+the `SPDX-License-Identifier` included. If the header does not work, you can -+use a smaller header or add the information for a specific file to the -+`REUSE.toml` file. + failf(data, "Unrecognized content encoding type. " +diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake +index 0f4db6982..dfabbefca 100644 +--- a/lib/curl_config.h.cmake ++++ b/lib/curl_config.h.cmake +@@ -796,3 +796,6 @@ ${SIZEOF_TIME_T_CODE} - You can manually verify the copyright and compliance status by running the --`./scripts/copyright.pl` script in the root of the git repository. -+[REUSE helper tool](https://github.com/fsfe/reuse-tool): `reuse lint` -diff --git a/docs/CURL-DISABLE.md b/docs/CURL-DISABLE.md -index 7978ed212..63de4026a 100644 ---- a/docs/CURL-DISABLE.md -+++ b/docs/CURL-DISABLE.md -@@ -1,3 +1,9 @@ -+ + /* Define to 1 to enable TLS-SRP support. */ + #cmakedefine USE_TLS_SRP 1 + - # Code defines to disable features and protocols - - ## `CURL_DISABLE_ALTSVC` -@@ -34,7 +40,11 @@ Disable support for the negotiate authentication methods. ++/* if ECH support is available */ ++#cmakedefine USE_ECH 1 +diff --git a/lib/dynhds.c b/lib/dynhds.c +index d7548959b..00f97506b 100644 +--- a/lib/dynhds.c ++++ b/lib/dynhds.c +@@ -56,6 +56,8 @@ entry_new(const char *name, size_t namelen, + e->valuelen = valuelen; + if(opts & DYNHDS_OPT_LOWERCASE) + Curl_strntolower(e->name, e->name, e->namelen); ++ if(opts & DYNHDS_OPT_LOWERCASE_VAL) ++ Curl_strntolower(e->value, e->value, e->valuelen); + return e; + } - ## `CURL_DISABLE_AWS` +@@ -138,6 +140,16 @@ void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts) + dynhds->opts = opts; + } --Disable **AWS-SIG4** support. -+Disable **aws-sigv4** support. ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts |= opt; ++} + -+## `CURL_DISABLE_CA_SEARCH` ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt) ++{ ++ dynhds->opts &= ~opt; ++} + -+Disable unsafe CA bundle search in PATH on Windows. + struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n) + { + DEBUGASSERT(dynhds); +diff --git a/lib/dynhds.h b/lib/dynhds.h +index 3b536000a..d7135698f 100644 +--- a/lib/dynhds.h ++++ b/lib/dynhds.h +@@ -53,6 +53,7 @@ struct dynhds { - ## `CURL_DISABLE_DICT` + #define DYNHDS_OPT_NONE (0) + #define DYNHDS_OPT_LOWERCASE (1 << 0) ++#define DYNHDS_OPT_LOWERCASE_VAL (1 << 1) -@@ -134,10 +144,19 @@ Disable the built-in progress meter + /** + * Init for use on first time or after a reset. +@@ -82,6 +83,8 @@ size_t Curl_dynhds_count(struct dynhds *dynhds); + * This will not have an effect on already existing headers. + */ + void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts); ++void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt); ++void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt); - Disable support for proxies + /** + * Return the n-th header entry or NULL if it does not exist. +diff --git a/lib/easy.c b/lib/easy.c +index dc4870608..4746133e9 100644 +--- a/lib/easy.c ++++ b/lib/easy.c +@@ -75,6 +75,8 @@ + #include "dynbuf.h" + #include "altsvc.h" + #include "hsts.h" ++#include "strcase.h" ++#include "impersonate.h" -+## `CURL_DISABLE_IPFS` -+ -+Disable the IPFS/IPNS protocols. This affects the curl tool only, where -+IPFS/IPNS protocol support is implemented. -+ - ## `CURL_DISABLE_RTSP` + #include "easy_lock.h" - Disable the RTSP protocol. +@@ -342,6 +344,221 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + return rc; + } -+## `CURL_DISABLE_SHA512_256` + -+Disable the SHA-512/256 hash algorithm. -+ - ## `CURL_DISABLE_SHUFFLE_DNS` - - Disable the shuffle DNS feature -@@ -166,3 +185,7 @@ Disable the TFTP protocol - ## `CURL_DISABLE_VERBOSE_STRINGS` - - Disable verbose strings and error messages. ++/* ++ * curl-impersonate: ++ * Actually call curl_easy_setopt() with all the needed options ++ * */ ++static CURLcode _do_impersonate(struct Curl_easy *data, ++ const struct impersonate_opts *opts, ++ int default_headers) ++{ ++ int i; ++ int ret; ++ struct curl_slist *headers = NULL; + -+## `CURL_DISABLE_WEBSOCKETS` ++ if(opts->target == NULL) { ++ DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", ++ opts->target)); ++ return CURLE_BAD_FUNCTION_ARGUMENT; ++ } + -+Disable the WebSocket protocols. -diff --git a/docs/CURLDOWN.md b/docs/CURLDOWN.md -index 8ee2f3ce4..18c1cbc3c 100644 ---- a/docs/CURLDOWN.md -+++ b/docs/CURLDOWN.md -@@ -1,3 +1,9 @@ -+ ++ if (opts->ssl_version != CURL_SSLVERSION_DEFAULT) { ++ ret = curl_easy_setopt(data, CURLOPT_SSLVERSION, opts->ssl_version); ++ if(ret) ++ return ret; ++ } + - # curldown - - A markdown-like syntax for libcurl man pages. -@@ -74,6 +80,7 @@ Each curldown starts with a header with meta-data: - - CURLOPT_HTTPAUTH (3) - TLS-backend: - - [name] -+ Added-in: [version or "n/a"] - --- - - All curldown files *must* have all the headers present and at least one -@@ -91,7 +98,7 @@ option. The available TLS backends are: - - `BearSSL` - - `GnuTLS` - - `mbedTLS` --- `OpenSSL` (also covers BoringSSL, libressl, quictls, AWS-LC and AmiSSL) -+- `OpenSSL` (also covers BoringSSL, LibreSSL, quictls, AWS-LC and AmiSSL) - - `rustls` - - `Schannel` - - `Secure Transport` -@@ -141,7 +148,15 @@ readable. - To make sure curldown documents render correctly as markdown, all literal - occurrences of `<` or `>` need to be escaped by a leading backslash. - --## symbols -+## Generating contents ++ if(opts->ciphers) { ++ ret = curl_easy_setopt(data, CURLOPT_SSL_CIPHER_LIST, opts->ciphers); ++ if (ret) ++ return ret; ++ } + -+`# %PROTOCOLS%` - inserts a **PROTOCOLS** section based on the metadata -+provided in the header. ++ if(opts->curves) { ++ ret = curl_easy_setopt(data, CURLOPT_SSL_EC_CURVES, opts->curves); ++ if(ret) ++ return ret; ++ } + -+`# %AVAILABILITY%` - inserts an **AVAILABILITY** section based on the metadata -+provided in the header. ++ if(opts->sig_hash_algs) { ++ ret = curl_easy_setopt(data, CURLOPT_SSL_SIG_HASH_ALGS, ++ opts->sig_hash_algs); ++ if(ret) ++ return ret; ++ } + -+## Symbols - - All mentioned curl symbols that have their own man pages, like - `curl_easy_perform(3)` are automatically rendered using italics in the output -diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md -index 6b6b5b46b..5e3551a45 100644 ---- a/docs/DEPRECATE.md -+++ b/docs/DEPRECATE.md -@@ -1,3 +1,9 @@ -+ ++ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_ALPN, opts->alpn ? 1 : 0); ++ if(ret) ++ return ret; + - # Items to be removed from future curl releases - - If any of these deprecated features is a cause for concern for you, please -@@ -6,47 +12,56 @@ email the - as soon as possible and explain to us why this is a problem for you and - how your use case cannot be satisfied properly using a workaround. - --## NTLM_WB auth -+## TLS libraries without 1.3 support ++ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_ALPS, opts->alps ? 1 : 0); ++ if(ret) ++ return ret; + -+curl drops support for TLS libraries without TLS 1.3 capability after May -+2025. ++ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_TICKET, ++ opts->tls_session_ticket ? 1 : 0); ++ if(ret) ++ return ret; + -+It requires that a curl build using the library should be able to negotiate -+and use TLS 1.3, or else it is not good enough. - --This NTLM authentication method is powered by a separate tool, --`ntlm_auth`. Barely anyone uses this method. It was always a quirky --implementation (including fork + exec), it has limited portability and we do --not test it in the test suite and CI. -+As of May 2024, the libraries that need to get fixed to remain supported after -+May 2025 are: BearSSL and Secure Transport. - --We keep the native NTLM implementation. -+## Hyper - --Due to a mistake, the `NTLM_WB` functionality is missing in builds since 8.4.0 --(October 2023). It needs to be manually patched to work. See [PR --12479](https://github.com/curl/curl/pull/12479). -+Hyper is an alternative HTTP backend for curl. It uses the hyper library and -+could in theory be used for HTTP/1, HTTP/2 and even HTTP/3 in the future with -+curl. - --curl removes the support for NTLM_WB auth in April 2024. -+The original plan and goal was that we would add this HTTP alternative (using -+a memory-safe library) and that users could eventually build and use libcurl -+exactly as previously but with parts of the core being more memory-safe. - --## space-separated `NOPROXY` patterns -+The hyper implementation ran into some snags and 10-15 tests and HTTP/2 -+support have remained disabled with hyper. For these reasons, hyper support -+has remained tagged EXPERIMENTAL. - --When specifying patterns/domain names for curl that should *not* go through a --proxy, the curl tool features the `--noproxy` command line option and the --library supports the `NO_PROXY` environment variable and the `CURLOPT_NOPROXY` --libcurl option. -+It is undoubtedly hard work to fix these remaining problems, as they typically -+require both rust and C knowledge in addition to deep HTTP familiarity. There -+does not seem to be that many persons interested or available for this -+challenge. Meanwhile, there is little if any demand for hyper from existing -+(lib)curl users. - --They all set the same list of patterns. This list is documented to be a set of --**comma-separated** names, but can also be provided separated with just --space. The ability to just use spaces for this has never been documented but --some users may still have come to rely on this. -+Finally: having support for hyper in curl has a significant cost: we need to -+maintain and develop a lot of functionality and tests twice to make sure -+libcurl works identically using either HTTP backend. - --Several other tools and utilities also parse the `NO_PROXY` environment --variable but do not consider a space to be a valid separator. Using spaces for --separator is probably less portable and might cause more friction than commas --do. Users should use commas for this for greater portability. -+The only way to keep hyper support in curl is to give it a good polish by -+someone with time, skill and energy to spend on this task. - --curl removes the support for space-separated names in July 2024. -+Unless a significant overhaul has proven to be in progress, hyper support is -+removed from curl in January 2025. - --## past removals -+## Past removals - - - Pipelining - - axTLS - - PolarSSL - - NPN -- - Support for systems without 64 bit data types -+ - Support for systems without 64-bit data types - - NSS - - gskit -- - mingw v1 -+ - MinGW v1 -+ - NTLM_WB -+ - space-separated `NOPROXY` patterns -diff --git a/docs/DISTROS.md b/docs/DISTROS.md -index 09e588c4f..93126afee 100644 ---- a/docs/DISTROS.md -+++ b/docs/DISTROS.md -@@ -1,17 +1,25 @@ -+ ++ // always enable this for browsers ++ ret = curl_easy_setopt(data, CURLOPT_TLS_STATUS_REQUEST, 1); ++ if(ret) ++ return ret; + - # curl distros - - - - Lots of organizations distribute curl packages to end users. This is a - collection of pointers to where to learn more about curl on and with each --distro. -+distro. Those marked *Rolling Release* typically run the latest version of curl -+and are therefore less likely to have back-ported patches to older versions. - - We discuss curl distro issues, patches and collaboration on the [curl-distros --mailing list](https://lists.haxx.se/listinfo/curl-distros). -+mailing list](https://lists.haxx.se/listinfo/curl-distros) ([list -+archives](https://curl.se/mail/list.cgi?list=curl-distros)). - - ## AlmaLinux - --- curl package source and patches: curl package source and patches -+- curl package source and patches: https://git.almalinux.org/rpms/curl/ - - curl issues: https://bugs.almalinux.org/view_all_bug_page.php click Category and choose curl - - curl security: https://errata.almalinux.org/ search for curl - -@@ -30,6 +38,8 @@ mailing list](https://lists.haxx.se/listinfo/curl-distros). - - ## Arch Linux - -+*Rolling Release* ++ if(opts->tls_permute_extensions) { ++ ret = curl_easy_setopt(data, CURLOPT_SSL_PERMUTE_EXTENSIONS, 1); ++ if(ret) ++ return ret; ++ } + - - curl: https://archlinux.org/packages/core/x86_64/curl/ - - curl issues: https://gitlab.archlinux.org/archlinux/packaging/packages/curl/-/issues - - curl security: https://security.archlinux.org/package/curl -@@ -37,6 +47,8 @@ mailing list](https://lists.haxx.se/listinfo/curl-distros). - - ## Buildroot - -+*Rolling Release* ++ if(opts->cert_compression) { ++ ret = curl_easy_setopt(data, ++ CURLOPT_SSL_CERT_COMPRESSION, ++ opts->cert_compression); ++ if(ret) ++ return ret; ++ } + - - curl package source and patches: https://git.buildroot.net/buildroot/tree/package/libcurl - - curl issues: https://bugs.buildroot.org/buglist.cgi?quicksearch=curl - -@@ -46,6 +58,8 @@ mailing list](https://lists.haxx.se/listinfo/curl-distros). - - ## Clear Linux - -+*Rolling Release* ++ if(default_headers) { ++ /* Build a linked list out of the static array of headers. */ ++ for(i = 0; i < IMPERSONATE_MAX_HEADERS; i++) { ++ if(opts->http_headers[i]) { ++ headers = curl_slist_append(headers, opts->http_headers[i]); ++ if(!headers) { ++ return CURLE_OUT_OF_MEMORY; ++ } ++ } ++ } + - - curl: https://github.com/clearlinux-pkgs/curl - - curl issues: https://github.com/clearlinux/distribution/issues - -@@ -69,7 +83,11 @@ mailing list](https://lists.haxx.se/listinfo/curl-distros). - - (this is the official curl binaries for Windows shipped by the curl project) - -+*Rolling Release* ++ if(headers) { ++ ret = curl_easy_setopt(data, CURLOPT_HTTPBASEHEADER, headers); ++ curl_slist_free_all(headers); ++ if(ret) ++ return ret; ++ } ++ } + - - curl: https://curl.se/windows/ -+- curl patches: https://github.com/curl/curl-for-win/blob/main/curl.patch (if any) -+- build-specific issues: https://github.com/curl/curl-for-win/issues - - Issues and patches for this are managed in the main curl project. - -@@ -77,6 +95,13 @@ Issues and patches for this are managed in the main curl project. - - - curl: https://cygwin.com/cgit/cygwin-packages/curl/tree/curl.cygport - - curl patches: https://cygwin.com/cgit/cygwin-packages/curl/tree -+- curl issues: https://inbox.sourceware.org/cygwin/?q=s%3Acurl -+ -+## Cygwin (cross mingw64) -+ -+- mingw64-x86_64-curl: https://cygwin.com/cgit/cygwin-packages/mingw64-x86_64-curl/tree/mingw64-x86_64-curl.cygport -+- mingw64-x86_64-curl patches: https://cygwin.com/cgit/cygwin-packages/mingw64-x86_64-curl/tree -+- mingw64-x86_64-curl issues: https://inbox.sourceware.org/cygwin/?q=s%3Amingw64-x86_64-curl - - ## Debian - -@@ -99,24 +124,32 @@ Issues and patches for this are managed in the main curl project. - - ## Gentoo Linux - -+*Rolling Release* -+ - - curl: https://packages.gentoo.org/packages/net-misc/curl - - curl issues: https://bugs.gentoo.org/buglist.cgi?quicksearch=net-misc/curl - - curl package sources and patches: https://gitweb.gentoo.org/repo/gentoo.git/tree/net-misc/curl/ - - ## GNU Guix - -+*Rolling Release* -+ - - curl: https://git.savannah.gnu.org/gitweb/?p=guix.git;a=blob;f=gnu/packages/curl.scm;hb=HEAD - - curl issues: https://issues.guix.gnu.org/search?query=curl - - ## Homebrew - -+*Rolling Release* -+ - - curl: https://formulae.brew.sh/formula/curl - - Homebrew's policy is that all patches and issues should be submitted upstream --unless it is very specific to Homebrew's way of packaging software. -+unless it is specific to Homebrew's way of packaging software. - - ## MacPorts - -+*Rolling Release* -+ - - curl: https://github.com/macports/macports-ports/tree/master/net/curl - - curl issues: https://trac.macports.org/query?0_port=curl&0_port_mode=%7E&0_status=%21closed - - curl patches: https://github.com/macports/macports-ports/tree/master/net/curl/files -@@ -131,12 +164,24 @@ unless it is very specific to Homebrew's way of packaging software. - - ## MSYS2 - -+*Rolling Release* -+ -+- curl: https://github.com/msys2/MSYS2-packages/tree/master/curl -+- curl issues: https://github.com/msys2/MSYS2-packages/issues -+- curl patches: https://github.com/msys2/MSYS2-packages/tree/master/curl (`*.patch`) -+ -+## MSYS2 (mingw-w64) -+ -+*Rolling Release* -+ - - curl: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl - - curl issues: https://github.com/msys2/MINGW-packages/issues - - curl patches: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl (`*.patch`) - - ## Muldersoft - -+*Rolling Release* -+ - - curl: https://github.com/lordmulder/cURL-build-win32 - - curl issues: https://github.com/lordmulder/cURL-build-win32/issues - - curl patches: https://github.com/lordmulder/cURL-build-win32/tree/master/patch -@@ -173,6 +218,8 @@ can also be used on other distributions - - ## OpenEmbedded / Yocto Project - -+*Rolling Release* -+ - - curl: https://layers.openembedded.org/layerindex/recipe/5765/ - - curl issues: https://bugzilla.yoctoproject.org/ - - curl patches: https://git.openembedded.org/openembedded-core/tree/meta/recipes-support/curl -@@ -218,16 +265,22 @@ can also be used on other distributions - - ## vcpkg - -+*Rolling Release* -+ - - curl: https://github.com/microsoft/vcpkg/tree/master/ports/curl - - curl issues: https://github.com/microsoft/vcpkg/issues - - curl patches: https://github.com/microsoft/vcpkg/tree/master/ports/curl (`*.patch`) - - ## Void Linux - -+*Rolling Release* -+ - - curl: https://github.com/void-linux/void-packages/tree/master/srcpkgs/curl - - curl issues: https://github.com/void-linux/void-packages/issues - - curl patches: https://github.com/void-linux/void-packages/tree/master/srcpkgs/curl/patches - - ## Wolfi - -+*Rolling Release* -+ - - curl: https://github.com/wolfi-dev/os/blob/main/curl.yaml -diff --git a/docs/EARLY-RELEASE.md b/docs/EARLY-RELEASE.md -index 3e9a679ac..e66dbbd44 100644 ---- a/docs/EARLY-RELEASE.md -+++ b/docs/EARLY-RELEASE.md -@@ -1,3 +1,9 @@ -+ -+ - # How to determine if an early patch release is warranted - - In the curl project we do releases every 8 weeks. Unless we break the cycle -diff --git a/docs/ECH.md b/docs/ECH.md -new file mode 100644 -index 000000000..572292dbc ---- /dev/null -+++ b/docs/ECH.md -@@ -0,0 +1,478 @@ -+ -+ -+# Building curl with HTTPS-RR and ECH support -+ -+We have added support for ECH to curl. It can use HTTPS RRs published in the -+DNS if curl uses DoH, or else can accept the relevant ECHConfigList values -+from the command line. This works with OpenSSL, wolfSSL or BoringSSL as the -+TLS provider. -+ -+This feature is EXPERIMENTAL. DO NOT USE IN PRODUCTION. -+ -+This should however provide enough of a proof-of-concept to prompt an informed -+discussion about a good path forward for ECH support in curl. -+ -+## OpenSSL Build -+ -+To build our ECH-enabled OpenSSL fork: -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/defo-project/openssl -+ cd openssl -+ ./config --libdir=lib --prefix=$HOME/code/openssl-local-inst -+ ...stuff... -+ make -j8 -+ ...stuff (maybe go for coffee)... -+ make install_sw -+ ...a little bit of stuff... -+``` -+ -+To build curl ECH-enabled, making use of the above: -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/curl/curl -+ cd curl -+ autoreconf -fi -+ LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech --enable-httpsrr -+ ...lots of output... -+ WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL... -+ make -+ ...lots more output... -+``` -+ -+If you do not get that WARNING at the end of the ``configure`` command, then -+ECH is not enabled, so go back some steps and re-do whatever needs re-doing:-) -+If you want to debug curl then you should add ``--enable-debug`` to the -+``configure`` command. -+ -+In a recent (2024-05-20) build on one machine, configure failed to find the -+ECH-enabled SSL library, apparently due to the existence of -+``$HOME/code/openssl-local-inst/lib/pkgconfig`` as a directory containing -+various settings. Deleting that directory worked around the problem but may -+not be the best solution. -+ -+## Using ECH and DoH -+ -+Curl supports using DoH for A/AAAA lookups so it was relatively easy to add -+retrieval of HTTPS RRs in that situation. To use ECH and DoH together: -+ -+```bash -+ cd $HOME/code/curl -+ LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech true --doh-url https://one.one.one.one/dns-query https://defo.ie/ech-check.php -+ ... -+ SSL_ECH_STATUS: success good
-+ ... -+``` -+ -+The output snippet above is within the HTML for the webpage, when things work. -+ -+The above works for these test sites: -+ -+```bash -+ https://defo.ie/ech-check.php -+ https://draft-13.esni.defo.ie:8413/stats -+ https://draft-13.esni.defo.ie:8414/stats -+ https://crypto.cloudflare.com/cdn-cgi/trace -+ https://tls-ech.dev -+``` -+ -+The list above has 4 different server technologies, implemented by 3 different -+parties, and includes a case (the port 8414 server) where HelloRetryRequest -+(HRR) is forced. -+ -+We currently support the following new curl command line arguments/options: -+ -+- ``--ech `` - the ``config`` value can be one of: -+ - ``false`` says to not attempt ECH -+ - ``true`` says to attempt ECH, if possible -+ - ``grease`` if attempting ECH is not possible, then send a GREASE ECH extension -+ - ``hard`` hard-fail the connection if ECH cannot be attempted -+ - ``ecl:`` a base64 encoded ECHConfigList, rather than one accessed from the DNS -+ - ``pn:`` override the ``public_name`` from an ECHConfigList -+ -+Note that in the above "attempt ECH" means the client emitting a TLS -+ClientHello with a "real" ECH extension, but that does not mean that the -+relevant server can succeed in decrypting, as things can fail for other -+reasons. -+ -+## Supplying an ECHConfigList on the command line -+ -+To supply the ECHConfigList on the command line, you might need a bit of -+cut-and-paste, e.g.: -+ -+```bash -+ dig +short https defo.ie -+ 1 . ipv4hint=213.108.108.101 ech=AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA ipv6hint=2a00:c6c0:0:116:5::10 -+``` -+ -+Then paste the base64 encoded ECHConfigList onto the curl command line: -+ -+```bash -+ LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl --ech ecl:AED+DQA8PAAgACD8WhlS7VwEt5bf3lekhHvXrQBGDrZh03n/LsNtAodbUAAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php -+ ... -+ SSL_ECH_STATUS: success good
-+ ... -+``` -+ -+The output snippet above is within the HTML for the webpage. -+ -+If you paste in the wrong ECHConfigList (it changes hourly for ``defo.ie``) you -+should get an error like this: -+ -+```bash -+ LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php -+ ... -+ * OpenSSL/3.3.0: error:0A00054B:SSL routines::ech required -+ ... -+``` -+ -+There is a reason to want this command line option - for use before publishing -+an ECHConfigList in the DNS as per the Internet-draft [A well-known URI for -+publishing ECHConfigList values](https://datatracker.ietf.org/doc/draft-ietf-tls-wkech/). -+ -+If you do use a wrong ECHConfigList value, then the server might return a -+good value, via the ``retry_configs`` mechanism. You can see that value in -+the verbose output, e.g.: -+ -+```bash -+ LD_LIBRARY_PATH=$HOME/code/openssl ./src/curl -vvv --ech ecl:AED+DQA8yAAgACDRMQo+qYNsNRNj+vfuQfFIkrrUFmM4vogucxKj/4nzYgAEAAEAAQANY292ZXIuZGVmby5pZQAA https://defo.ie/ech-check.php -+ ... -+* ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8cQAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA -+* ECH: retry_configs for defo.ie from cover.defo.ie, 319 -+ ... -+``` -+ -+At that point, you could copy the base64 encoded value above and try again. -+For now, this only works for the OpenSSL and BoringSSL builds. -+ -+## Default settings -+ -+Curl has various ways to configure default settings, e.g. in ``$HOME/.curlrc``, -+so one can set the DoH URL and enable ECH that way: -+ -+```bash -+ cat ~/.curlrc -+ doh-url=https://one.one.one.one/dns-query -+ silent -+ ech=true -+``` -+ -+Note that when you use the system's curl command (rather than our ECH-enabled -+build), it is liable to warn that ``ech`` is an unknown option. If that is an -+issue (e.g. if some script re-directs stdout and stderr somewhere) then adding -+the ``silent`` line above seems to be a good enough fix. (Though of -+course, yet another script could depend on non-silent behavior, so you may have -+to figure out what you prefer yourself.) That seems to have changed with the -+latest build, previously ``silent=TRUE`` was what I used in ``~/.curlrc`` but -+now that seems to cause a problem, so that the following line(s) are ignored. -+ -+If you want to always use our OpenSSL build you can set ``LD_LIBRARY_PATH`` -+in the environment: -+ -+```bash -+ export LD_LIBRARY_PATH=$HOME/code/openssl -+``` -+ -+When you do the above, there can be a mismatch between OpenSSL versions -+for applications that check that. A ``git push`` for example fails so you -+should unset ``LD_LIBRARY_PATH`` before doing that or use a different shell. -+ -+```bash -+ git push -+ OpenSSL version mismatch. Built against 30000080, you have 30200000 -+ ... -+``` -+ -+With all that setup as above the command line gets simpler: -+ -+```bash -+ ./src/curl https://defo.ie/ech-check.php -+ ... -+ SSL_ECH_STATUS: success good
-+ ... -+``` -+ -+The ``--ech true`` option is opportunistic, so tries to do ECH but does not fail if -+the client for example cannot find any ECHConfig values. The ``--ech hard`` -+option hard-fails if there is no ECHConfig found in DNS, so for now, that is not -+a good option to set as a default. Once ECH has really been attempted by -+the client, if decryption on the server side fails, then curl fails. -+ -+## Code changes for ECH support when using DoH -+ -+Code changes are ``#ifdef`` protected via ``USE_ECH`` or ``USE_HTTPSRR``: -+ -+- ``USE_HTTPSRR`` is used for HTTPS RR retrieval code that could be generically -+ used should non-ECH uses for HTTPS RRs be identified, e.g. use of ALPN values -+or IP address hints. -+ -+- ``USE_ECH`` protects ECH specific code. -+ -+There are various obvious code blocks for handling the new command line -+arguments which are not described here, but should be fairly clear. -+ -+As shown in the ``configure`` usage above, there are ``configure.ac`` changes -+that allow separately dis/enabling ``USE_HTTPSRR`` and ``USE_ECH``. If ``USE_ECH`` -+is enabled, then ``USE_HTTPSRR`` is forced. In both cases ``USE_DOH`` -+is required. (There may be some configuration conflicts available for the -+determined:-) -+ -+The main functional change, as you would expect, is in ``lib/vtls/openssl.c`` -+where an ECHConfig, if available from command line or DNS cache, is fed into -+the OpenSSL library via the new APIs implemented in our OpenSSL fork for that -+purpose. This code also implements the opportunistic (``--ech true``) or hard-fail -+(``--ech hard``) logic. -+ -+Other than that, the main additions are in ``lib/doh.c`` -+where we reuse ``dohprobe()`` to retrieve an HTTPS RR value for the target -+domain. If such a value is found, that is stored using a new ``doh_store_https()`` -+function in a new field in the ``dohentry`` structure. -+ -+The qname for the DoH query is modified if the port number is not 443, as -+defined in the SVCB specification. -+ -+When the DoH process has worked, ``Curl_doh_is_resolved()`` now also returns -+the relevant HTTPS RR value data in the ``Curl_dns_entry`` structure. -+That is later accessed when the TLS session is being established, if ECH is -+enabled (from ``lib/vtls/openssl.c`` as described above). -+ -+## Limitations -+ -+Things that need fixing, but that can probably be ignored for the -+moment: -+ -+- We could easily add code to make use of an ``alpn=`` value found in an HTTPS -+ RR, passing that on to OpenSSL for use as the "inner" ALPN value, but have -+yet to do that. -+ -+Current limitations (more interesting than the above): -+ -+- Only the first HTTPS RR value retrieved is actually processed as described -+ above, that could be extended in future, though picking the "right" HTTPS RR -+could be non-trivial if multiple RRs are published - matching IP address hints -+versus A/AAAA values might be a good basis for that. Last I checked though, -+browsers supporting ECH did not handle multiple HTTPS RRs well, though that -+needs re-checking as it has been a while. -+ -+- It is unclear how one should handle any IP address hints found in an HTTPS RR. -+ It may be that a bit of consideration of how "multi-CDN" deployments might -+emerge would provide good answers there, but for now, it is not clear how best -+curl might handle those values when present in the DNS. -+ -+- The SVCB/HTTPS RR specification supports a new "CNAME at apex" indirection -+ ("aliasMode") - the current code takes no account of that at all. One could -+envisage implementing the equivalent of following CNAMEs in such cases, but -+it is not clear if that'd be a good plan. (As of now, chrome browsers do not seem -+to have any support for that "aliasMode" and we have not checked Firefox for that -+recently.) -+ -+- We have not investigated what related changes or additions might be needed -+ for applications using libcurl, as opposed to use of curl as a command line -+tool. -+ -+- We have not yet implemented tests as part of the usual curl test harness as -+doing so would seem to require re-implementing an ECH-enabled server as part -+of the curl test harness. For now, we have a ``./tests/ech_test.sh`` script -+that attempts ECH with various test servers and with many combinations of the -+allowed command line options. While that is a useful test and has find issues, -+it is not comprehensive and we are not (as yet) sure what would be the right -+level of coverage. When running that script you should not have a -+``$HOME/.curlrc`` file that affects ECH or some of the negative tests could -+produce spurious failures. -+ -+## Building with cmake -+ -+To build with cmake, assuming our ECH-enabled OpenSSL is as before: -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/curl/curl -+ cd curl -+ mkdir build -+ cd build -+ cmake -DOPENSSL_ROOT_DIR=$HOME/code/openssl -DUSE_ECH=1 -DUSE_HTTPSRR=1 .. -+ ... -+ make -+ ... -+ [100%] Built target curl -+``` -+ -+The binary produced by the cmake build does not need any ECH-specific -+``LD_LIBRARY_PATH`` setting. -+ -+## BoringSSL build -+ -+BoringSSL is also supported by curl and also supports ECH, so to build -+with that, instead of our ECH-enabled OpenSSL: -+ -+```bash -+ cd $HOME/code -+ git clone https://boringssl.googlesource.com/boringssl -+ cd boringssl -+ cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/code/boringssl/inst -DBUILD_SHARED_LIBS=1 -+ make -+ ... -+ make install -+``` -+ -+Then: -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/curl/curl -+ cd curl -+ autoreconf -fi -+ LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech --enable-httpsrr -+ ...lots of output... -+ WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution. -+ make -+``` -+ -+The BoringSSL APIs are fairly similar to those in our ECH-enabled OpenSSL -+fork, so code changes are also in ``lib/vtls/openssl.c``, protected -+via ``#ifdef OPENSSL_IS_BORINGSSL`` and are mostly obvious API variations. -+ -+The BoringSSL APIs however do not support the ``--ech pn:`` command line -+variant as of now. -+ -+## wolfSSL build -+ -+wolfSSL also supports ECH and can be used by curl, so here's how: -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/wolfSSL/wolfssl -+ cd wolfssl -+ ./autogen.sh -+ ./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra -+ make -+ make install -+``` -+ -+The install prefix (``inst``) in the above causes wolfSSL to be installed there -+and we seem to need that for the curl configure command to work out. The -+``--enable-opensslextra`` turns out (after much faffing about;-) to be -+important or else we get build problems with curl below. -+ -+```bash -+ cd $HOME/code -+ git clone https://github.com/curl/curl -+ cd curl -+ autoreconf -fi -+ ./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech --enable-httpsrr -+ make -+``` -+ -+There are some known issues with the ECH implementation in wolfSSL: -+ -+- The main issue is that the client currently handles HelloRetryRequest -+ incorrectly. [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).) -+ The HRR issue means that the client does not work for -+ [this ECH test web site](https://tls-ech.dev) and any other similarly configured -+ sites. -+- There is also an issue related to so-called middlebox compatibility mode. -+ [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774) -+ -+### Code changes to support wolfSSL -+ -+There are what seem like oddball differences: -+ -+- The DoH URL in``$HOME/.curlrc`` can use `1.1.1.1` for OpenSSL but has to be -+ `one.one.one.one` for wolfSSL. The latter works for both, so OK, we us that. -+- There seems to be some difference in CA databases too - the wolfSSL version -+ does not like ``defo.ie``, whereas the system and OpenSSL ones do. We can -+ ignore that for our purposes via ``--insecure``/``-k`` but would need to fix -+ for a real setup. (Browsers do like those certificates though.) -+ -+Then there are some functional code changes: -+ -+- tweak to ``configure.ac`` to check if wolfSSL has ECH or not -+- added code to ``lib/vtls/wolfssl.c`` mirroring what's done in the -+ OpenSSL equivalent above. -+- wolfSSL does not support ``--ech false`` or the ``--ech pn:`` command line -+ argument. ++ if(opts->http2_pseudo_headers_order) { ++ ret = curl_easy_setopt(data, ++ CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, ++ opts->http2_pseudo_headers_order); ++ if(ret) ++ return ret; ++ } + -+The lack of support for ``--ech false`` is because wolfSSL has decided to -+always at least GREASE if built to support ECH. In other words, GREASE is -+a compile time choice for wolfSSL, but a runtime choice for OpenSSL or -+BoringSSL. (Both are reasonable.) ++ if(opts->http2_settings) { ++ ret = curl_easy_setopt(data, CURLOPT_HTTP2_SETTINGS, opts->http2_settings); ++ if(ret) ++ return ret; ++ } + -+## Additional notes ++ if(opts->http2_window_update) { ++ ret = curl_easy_setopt(data, CURLOPT_HTTP2_WINDOW_UPDATE, opts->http2_window_update); ++ if(ret) ++ return ret; ++ } + -+### Supporting ECH without DoH ++ if(opts->http2_streams) { ++ ret = curl_easy_setopt(data, CURLOPT_HTTP2_STREAMS, opts->http2_streams); ++ if(ret) ++ return ret; ++ } + -+All of the above only applies if DoH is being used. There should be a use-case -+for ECH when DoH is not used by curl - if a system stub resolver supports DoT -+or DoH, then, considering only ECH and the network threat model, it would make -+sense for curl to support ECH without curl itself using DoH. The author for -+example uses a combination of stubby+unbound as the system resolver listening -+on localhost:53, so would fit this use-case. That said, it is unclear if -+this is a niche that is worth trying to address. (The author is just as happy to -+let curl use DoH to talk to the same public recursive that stubby might use:-) ++ if(opts->ech) { ++ ret = curl_easy_setopt(data, CURLOPT_ECH, opts->ech); ++ if(ret) ++ return ret; ++ } + -+Assuming for the moment this is a use-case we would like to support, then if -+DoH is not being used by curl, it is not clear at this time how to provide -+support for ECH. One option would seem to be to extend the ``c-ares`` library -+to support HTTPS RRs, but in that case it is not now clear whether such -+changes would be attractive to the ``c-ares`` maintainers, nor whether the -+"tag=value" extensibility inherent in the HTTPS/SVCB specification is a good -+match for the ``c-ares`` approach of defining structures specific to decoded -+answers for each supported RRtype. We are also not sure how many downstream -+curl deployments actually make use of the ``c-ares`` library, which would -+affect the utility of such changes. Another option might be to consider using -+some other generic DNS library that does support HTTPS RRs, but it is unclear -+if such a library could or would be used by all or almost all curl builds and -+downstream releases of curl. ++ if(opts->tls_grease) { ++ ret = curl_easy_setopt(data, CURLOPT_TLS_GREASE, opts->tls_grease); ++ } + -+Our current conclusion is that doing the above is likely best left until we -+have some experience with the "using DoH" approach, so we are going to punt on -+this for now. ++ if(opts->tls_extension_order) { ++ // printf("setting extension order as: %s\n", opts->tls_extension_order); ++ ret = curl_easy_setopt(data, CURLOPT_TLS_EXTENSION_ORDER, opts->tls_extension_order); ++ } + -+### Debugging ++ if(opts->http2_stream_weight) { ++ ret = curl_easy_setopt(data, CURLOPT_STREAM_WEIGHT, opts->http2_stream_weight); ++ } + -+Just a note to self as remembering this is a nuisance: ++ if(opts->http2_stream_exclusive) { ++ ret = curl_easy_setopt(data, CURLOPT_STREAM_EXCLUSIVE, opts->http2_stream_exclusive); ++ } + -+```bash -+LD_LIBRARY_PATH=$HOME/code/openssl:./lib/.libs gdb ./src/.libs/curl -+``` ++ /* Always enable all supported compressions. */ ++ ret = curl_easy_setopt(data, CURLOPT_ACCEPT_ENCODING, ""); ++ if(ret) ++ return ret; + -+### Localhost testing ++ return CURLE_OK; ++} + -+It can be useful to be able to run against a localhost OpenSSL ``s_server`` -+for testing. We have published instructions for such -+[localhost tests](https://github.com/defo-project/ech-dev-utils/blob/main/howtos/localhost-tests.md) -+in another repository. Once you have that set up, you can start a server -+and then run curl against that: + -+```bash -+ cd $HOME/code/ech-dev-utils -+ ./scripts/echsvr.sh -d -+ ... -+``` ++/* ++ * curl-impersonate: ++ * Call curl_easy_setopt() with all the needed options as defined by the target ++ * */ ++CURLcode curl_easy_impersonate_customized(struct Curl_easy *data, ++ const struct impersonate_opts *opts, ++ int default_headers) ++{ ++ int ret; + -+The ``echsvr.sh`` script supports many ECH-related options. Use ``echsvr.sh -h`` -+for details. ++ ret = _do_impersonate(data, opts, default_headers); ++ if(ret) ++ return ret; + -+In another window: ++ return CURLE_OK; ++} + -+```bash -+ cd $HOME/code/curl/ -+ ./src/curl -vvv --insecure --connect-to foo.example.com:8443:localhost:8443 --ech ecl:AD7+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAA== -+``` ++/* ++ * curl-impersonate: ++ * Call curl_easy_setopt() with all the needed options as defined in the ++ * 'impersonations' array. ++ * */ ++CURLcode curl_easy_impersonate(struct Curl_easy *data, const char *target, ++ int default_headers) ++{ ++ int ret; ++ const struct impersonate_opts *opts = NULL; + -+### Automated use of ``retry_configs`` not supported so far... ++ for(opts = impersonations; opts->target != NULL; opts++) { ++ if (strcasecompare(target, opts->target)) { ++ break; ++ } ++ } + -+As of now we have not added support for using ``retry_config`` handling in the -+application - for a command line tool, one can just use ``dig`` (or ``kdig``) -+to get the HTTPS RR and pass the ECHConfigList from that on the command line, -+if needed, or one can access the value from command line output in verbose more -+and then reuse that in another invocation. ++ if(opts->target == NULL) { ++ DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", ++ target)); ++ return CURLE_BAD_FUNCTION_ARGUMENT; ++ } + -+Both our OpenSSL fork and BoringSSL have APIs for both controlling GREASE and -+accessing and logging ``retry_configs``, it seems wolfSSL has neither. -diff --git a/docs/EXPERIMENTAL.md b/docs/EXPERIMENTAL.md -index ee26ac110..e88094242 100644 ---- a/docs/EXPERIMENTAL.md -+++ b/docs/EXPERIMENTAL.md -@@ -1,3 +1,9 @@ -+ ++ return CURLE_OK; ++} + - # Experimental + /* + * curl_easy_init() is the external interface to alloc, setup and init an + * easy handle that is returned. If anything goes wrong, NULL is returned. +@@ -350,6 +567,8 @@ struct Curl_easy *curl_easy_init(void) + { + CURLcode result; + struct Curl_easy *data; ++ char *env_target; ++ char *env_headers; - Some features and functionality in curl and libcurl are considered -@@ -16,9 +22,52 @@ Experimental support in curl means: - experimental. - 5. Experimental features are clearly marked so in documentation. Beware. + /* Make sure we inited the global SSL stuff */ + global_init_lock(); +@@ -372,6 +591,29 @@ struct Curl_easy *curl_easy_init(void) + return NULL; + } -+## Graduation -+ -+1. Each experimental feature should have a set of documented requirements of -+ what is needed for that feature to graduate. Graduation means being removed -+ from the list of experiments. -+2. An experiment should NOT graduate if it needs test cases to be disabled, -+ unless they are for minor features that are clearly documented as not -+ provided by the experiment and then the disabling should be managed inside -+ each affected test case. ++ /* ++ * curl-impersonate: Hook into curl_easy_init() to set the required options ++ * from an environment variable. ++ * This is a bit hacky but allows seamless integration of libcurl-impersonate ++ * without code modifications to the app. ++ */ ++ env_target = curl_getenv("CURL_IMPERSONATE"); ++ if(env_target) { ++ env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); ++ if(env_headers) { ++ result = curl_easy_impersonate(data, env_target, ++ !strcasecompare(env_headers, "no")); ++ free(env_headers); ++ } else { ++ result = curl_easy_impersonate(data, env_target, true); ++ } ++ free(env_target); ++ if(result) { ++ Curl_close(&data); ++ return NULL; ++ } ++ } + - ## Experimental features right now + return data; + } -- - The Hyper HTTP backend -- - HTTP/3 support (using the quiche or msh3 backends) -- - The rustls backend -- - WebSocket -+### The Hyper HTTP backend -+ -+Graduation requirements: -+ -+- HTTP/1 and HTTP/2 support, including multiplexing -+ -+(Hyper is marked for deprecation. It cannot graduate.) -+ -+### HTTP/3 support (non-ngtcp2 backends) -+ -+Graduation requirements: -+ -+- The used libraries should be considered out-of-beta with a reasonable -+ expectation of a stable API going forward. -+ -+- Using HTTP/3 with the given build should perform without risking busy-loops -+ -+### The Rustls backend -+ -+Graduation requirements: -+ -+- a reasonable expectation of a stable API going forward. -+ -+## ECH -+ -+Use of the HTTPS resource record and Encrypted Client Hello (ECH) when using -+DoH -+ -+Graduation requirements: -+ -+- ECH support exists in at least one widely used TLS library apart from -+ BoringSSL and wolfSSL. +@@ -952,6 +1194,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) + outcurl->state.referer_alloc = TRUE; + } + ++ if(data->state.base_headers) { ++ outcurl->state.base_headers = ++ Curl_slist_duplicate(data->state.base_headers); ++ if(!outcurl->state.base_headers) ++ goto fail; ++ } + -+- feedback from users saying that ECH works for their use cases + /* Reinitialize an SSL engine for the new handle + * note: the engine name has already been copied by dupset */ + if(outcurl->set.str[STRING_SSL_ENGINE]) { +@@ -1040,6 +1289,9 @@ fail: + */ + void curl_easy_reset(struct Curl_easy *data) + { ++ char *env_target; ++ char *env_headers; + -+- it has been given time to mature, so no earlier than April 2025 (twelve -+ months after being added here) -diff --git a/docs/FAQ b/docs/FAQ -index 1450a1e75..943a74199 100644 ---- a/docs/FAQ -+++ b/docs/FAQ -@@ -56,7 +56,7 @@ FAQ - 4. Running Problems - 4.2 Why do I get problems when I use & or % in the URL? - 4.3 How can I use {, }, [ or ] to specify multiple URLs? -- 4.4 Why do I get downloaded data even though the web page does not exist? -+ 4.4 Why do I get downloaded data even though the webpage does not exist? - 4.5 Why do I get return code XXX from an HTTP server? - 4.5.1 "400 Bad Request" - 4.5.2 "401 Unauthorized" -@@ -65,7 +65,7 @@ FAQ - 4.5.5 "405 Method Not Allowed" - 4.5.6 "301 Moved Permanently" - 4.6 Can you tell me what error code 142 means? -- 4.7 How do I keep user names and passwords secret in curl command lines? -+ 4.7 How do I keep usernames and passwords secret in curl command lines? - 4.8 I found a bug - 4.9 curl cannot authenticate to a server that requires NTLM? - 4.10 My HTTP request using HEAD, PUT or DELETE does not work -@@ -84,12 +84,12 @@ FAQ - 5.1 Is libcurl thread-safe? - 5.2 How can I receive all data into a large memory chunk? - 5.3 How do I fetch multiple files with libcurl? -- 5.4 Does libcurl do Winsock initialization on win32 systems? -- 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ? -+ 5.4 Does libcurl do Winsock initialization on Win32 systems? -+ 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on Win32 ? - 5.6 What about Keep-Alive or persistent connections? - 5.7 Link errors when building libcurl on Windows - 5.8 libcurl.so.X: open failed: No such file or directory -- 5.9 How does libcurl resolve host names? -+ 5.9 How does libcurl resolve hostnames? - 5.10 How do I prevent libcurl from writing the response to stdout? - 5.11 How do I make libcurl not receive the whole HTTP response? - 5.12 Can I make libcurl fake or hide my real IP address? -@@ -407,7 +407,7 @@ FAQ - The reason why static libraries is much harder to deal with is that for them - we do not get any help but the script itself must know or check what more - libraries that are needed (with shared libraries, that dependency "chain" is -- handled automatically). This is a error-prone process and one that also -+ handled automatically). This is an error-prone process and one that also - tends to vary over time depending on the release versions of the involved - components and may also differ between operating systems. - -@@ -423,8 +423,8 @@ FAQ - backends. - - curl can be built to use one of the following SSL alternatives: OpenSSL, -- libressl, BoringSSL, AWS-LC, GnuTLS, wolfSSL, mbedTLS, Secure Transport -- (native iOS/OS X), Schannel (native Windows), BearSSL or Rustls. They all -+ LibreSSL, BoringSSL, AWS-LC, GnuTLS, wolfSSL, mbedTLS, Secure Transport -+ (native iOS/macOS), Schannel (native Windows), BearSSL or Rustls. They all - have their pros and cons, and we try to maintain a comparison of them here: - https://curl.se/docs/ssl-compared.html - -@@ -566,7 +566,7 @@ FAQ - 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP? - - curl adheres to the HTTP spec, which basically means you can play with *any* -- protocol that is built on top of HTTP. Protocols such as SOAP, WEBDAV and -+ protocol that is built on top of HTTP. Protocols such as SOAP, WebDAV and - XML-RPC are all such ones. You can use -X to set custom requests and -H to - set custom headers (or replace internally generated ones). - -@@ -604,7 +604,7 @@ FAQ - curl -d ' with spaces ' example.com - - Exactly what kind of quotes and how to do this is entirely up to the shell -- or command line interpreter that you are using. For most unix shells, you -+ or command line interpreter that you are using. For most Unix shells, you - can more or less pick either single (') or double (") quotes. For - Windows/DOS command prompts you must use double (") quotes, and if the - option string contains inner double quotes you can escape them with a -@@ -624,7 +624,7 @@ FAQ - - 3.14 Does curl support JavaScript or PAC (automated proxy config)? - -- Many web pages do magic stuff using embedded JavaScript. curl and libcurl -+ Many webpages do magic stuff using embedded JavaScript. curl and libcurl - have no built-in support for that, so it will be treated just like any other - contents. - -@@ -722,7 +722,7 @@ FAQ - - curl --header "Host: www.example.com" http://127.0.0.1/ - -- You can also opt to add faked host name entries to curl with the --resolve -+ You can also opt to add faked hostname entries to curl with the --resolve - option. That has the added benefit that things like redirects will also work - properly. The above operation would instead be done as: - -@@ -771,11 +771,10 @@ FAQ - [WHATEVER]. This way you can for example send a DELETE by doing "curl -X - DELETE [URL]". - -- It is thus pointless to do "curl -XGET [URL]" as GET would be used -- anyway. In the same vein it is pointless to do "curl -X POST -d data -- [URL]"... But you can make a fun and somewhat rare request that sends a -- request-body in a GET request with something like "curl -X GET -d data -- [URL]" -+ It is thus pointless to do "curl -XGET [URL]" as GET would be used anyway. -+ In the same vein it is pointless to do "curl -X POST -d data [URL]". You can -+ make a fun and somewhat rare request that sends a request-body in a GET -+ request with something like "curl -X GET -d data [URL]" - - Note that -X does not actually change curl's behavior as it only modifies the - actual string sent in the request, but that may of course trigger a -@@ -822,7 +821,7 @@ FAQ - - curl -g 'www.example.com/weirdname[].html' - -- 4.4 Why do I get downloaded data even though the web page does not exist? -+ 4.4 Why do I get downloaded data even though the webpage does not exist? - - curl asks remote servers for the page you specify. If the page does not exist - at the server, the HTTP protocol defines how the server should respond and -@@ -883,7 +882,7 @@ FAQ - appreciate a detailed bug report from you that describes how we could go - ahead and repeat this. - -- 4.7 How do I keep user names and passwords secret in curl command lines? -+ 4.7 How do I keep usernames and passwords secret in curl command lines? - - This problem has two sides: - -@@ -1100,7 +1099,7 @@ FAQ - When doing HTTP transfers, curl will perform exactly what you are asking it - to do and if successful it will not return an error. You can use curl to - test your web server's "file not found" page (that gets 404 back), you can -- use it to check your authentication protected web pages (that gets a 401 -+ use it to check your authentication protected webpages (that gets a 401 - back) and so on. - - The specific HTTP response code does not constitute a problem or error for -@@ -1175,11 +1174,11 @@ FAQ - only reusable, but you are even encouraged to reuse it if you can, as that - will enable libcurl to use persistent connections. - -- 5.4 Does libcurl do Winsock initialization on win32 systems? -+ 5.4 Does libcurl do Winsock initialization on Win32 systems? - - Yes, if told to in the curl_global_init() call. - -- 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ? -+ 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on Win32 ? - - Yes, but you cannot open a FILE * and pass the pointer to a DLL and have - that DLL use the FILE * (as the DLL and the client application cannot access -@@ -1192,7 +1191,7 @@ FAQ - 5.6 What about Keep-Alive or persistent connections? - - curl and libcurl have excellent support for persistent connections when -- transferring several files from the same server. curl will attempt to reuse -+ transferring several files from the same server. curl will attempt to reuse - connections for all URLs specified on the same command line/config file, and - libcurl will reuse connections for all transfers that are made using the - same libcurl handle. -@@ -1252,14 +1251,14 @@ FAQ - - 'man ld.so' and 'man ld' will tell you more details - -- 5.9 How does libcurl resolve host names? -+ 5.9 How does libcurl resolve hostnames? + Curl_req_hard_reset(&data->req, data); - libcurl supports a large number of name resolve functions. One of them is - picked at build-time and will be used unconditionally. Thus, if you want to - change name resolver function you must rebuild libcurl and tell it to use a - different function. + /* zero out UserDefined data: */ +@@ -1064,6 +1316,23 @@ void curl_easy_reset(struct Curl_easy *data) + #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) + Curl_http_auth_cleanup_digest(data); + #endif ++ ++ /* ++ * curl-impersonate: Hook into curl_easy_reset() to set the required options ++ * from an environment variable, just like in curl_easy_init(). ++ */ ++ env_target = curl_getenv("CURL_IMPERSONATE"); ++ if(env_target) { ++ env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); ++ if(env_headers) { ++ curl_easy_impersonate(data, env_target, ++ !strcasecompare(env_headers, "no")); ++ free(env_headers); ++ } else { ++ curl_easy_impersonate(data, env_target, true); ++ } ++ free(env_target); ++ } + } -- - The non-IPv6 resolver that can use one of four different host name resolve -+ - The non-IPv6 resolver that can use one of four different hostname resolve - calls (depending on what your system supports): + /* +diff --git a/lib/easyoptions.c b/lib/easyoptions.c +index 9c4438a10..86068cf12 100644 +--- a/lib/easyoptions.c ++++ b/lib/easyoptions.c +@@ -86,6 +86,7 @@ struct curl_easyoption Curl_easyopts[] = { + {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0}, + {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, + {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0}, ++ {"ECH", CURLOPT_ECH, CURLOT_STRING, 0}, + {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0}, + {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS}, + {"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0}, +@@ -133,8 +134,14 @@ struct curl_easyoption Curl_easyopts[] = { + {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0}, + {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0}, + {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, ++ {"HTTP2_PSEUDO_HEADERS_ORDER", CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, ++ CURLOT_STRING, 0}, ++ {"HTTP2_SETTINGS", CURLOPT_HTTP2_SETTINGS, CURLOT_STRING, 0}, ++ {"HTTP2_STREAMS", CURLOPT_HTTP2_STREAMS, CURLOT_STRING, 0}, ++ {"HTTP2_WINDOW_UPDATE", CURLOPT_HTTP2_WINDOW_UPDATE, CURLOT_LONG, 0}, + {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0}, + {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0}, ++ {"HTTPBASEHEADER", CURLOPT_HTTPBASEHEADER, CURLOT_SLIST, 0}, + {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, + {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, + {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, +@@ -307,21 +314,27 @@ struct curl_easyoption Curl_easyopts[] = { + {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0}, + {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0}, + {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0}, ++ {"SSL_CERT_COMPRESSION", CURLOPT_SSL_CERT_COMPRESSION, CURLOT_STRING, 0}, + {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0}, + {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0}, + {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0}, + {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0}, + {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0}, ++ {"SSL_ENABLE_ALPS", CURLOPT_SSL_ENABLE_ALPS, CURLOT_LONG, 0}, + {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0}, ++ {"SSL_ENABLE_TICKET", CURLOPT_SSL_ENABLE_TICKET, CURLOT_LONG, 0}, + {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0}, + {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0}, ++ {"SSL_PERMUTE_EXTENSIONS", CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOT_LONG, 0}, + {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0}, ++ {"SSL_SIG_HASH_ALGS", CURLOPT_SSL_SIG_HASH_ALGS, CURLOT_STRING, 0}, + {"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0}, + {"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0}, + {"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, + {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0}, + {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0}, + {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0}, ++ {"STREAM_EXCLUSIVE", CURLOPT_STREAM_EXCLUSIVE, CURLOT_LONG, 0}, + {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0}, + {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS, + CURLOT_LONG, 0}, +@@ -342,6 +355,11 @@ struct curl_easyoption Curl_easyopts[] = { + {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0}, + {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0}, + {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0}, ++ {"TLS_EXTENSION_ORDER", CURLOPT_TLS_EXTENSION_ORDER, CURLOT_STRING, 0}, ++ {"TLS_GREASE", CURLOPT_TLS_GREASE, CURLOT_LONG, 0}, ++ {"TLS_KEY_USAGE_NO_CHECK", CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOT_LONG, 0}, ++ {"TLS_SIGNED_CERT_TIMESTAMPS", CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, CURLOT_LONG, 0}, ++ {"TLS_STATUS_REQUEST", CURLOPT_TLS_STATUS_REQUEST, CURLOT_LONG, 0}, + {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0}, + {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0}, + {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0}, +@@ -375,6 +393,6 @@ struct curl_easyoption Curl_easyopts[] = { + */ + int Curl_easyopts_check(void) + { +- return ((CURLOPT_LASTENTRY%10000) != (324 + 1)); ++ return ((CURLOPT_LASTENTRY%10000) != (1013 + 1)); + } + #endif +diff --git a/lib/http.c b/lib/http.c +index 92c04e69c..84ece2a16 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -91,6 +91,7 @@ + #include "ws.h" + #include "c-hyper.h" + #include "curl_ctype.h" ++#include "slist.h" - A - gethostbyname() -@@ -1353,7 +1352,7 @@ FAQ - then you have to work with what you are given. The LIST output format is - entirely at the server's own liking and the NLST output does not reveal any - types and in many cases does not even include all the directory entries. -- Also, both LIST and NLST tend to hide unix-style hidden files (those that -+ Also, both LIST and NLST tend to hide Unix-style hidden files (those that - start with a dot) by default so you need to do "LIST -a" or similar to see - them. + /* The last 3 #include files should be in this order */ + #include "curl_printf.h" +@@ -1451,6 +1452,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, + int numlists = 1; /* by default */ + int i; -diff --git a/docs/FEATURES.md b/docs/FEATURES.md -index bae38fb85..f36615494 100644 ---- a/docs/FEATURES.md -+++ b/docs/FEATURES.md -@@ -1,3 +1,9 @@ -+ ++ /* ++ * curl-impersonate: Use the merged list of headers if it exists (i.e. when ++ * the CURLOPT_HTTPBASEHEADER option was set. ++ */ ++ struct curl_slist *noproxyheaders = ++ (data->state.merged_headers ? ++ data->state.merged_headers : ++ data->set.headers); + - # Features -- what curl can do + #ifndef CURL_DISABLE_PROXY + enum proxy_use proxy; + +@@ -1462,10 +1472,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, - ## curl tool -@@ -6,7 +12,6 @@ - - multiple URLs in a single command line - - range "globbing" support: [0-13], {one,two,three} - - multiple file upload on a single command line -- - custom maximum transfer rate - - redirect stderr - - parallel transfers + switch(proxy) { + case HEADER_SERVER: +- h[0] = data->set.headers; ++ h[0] = noproxyheaders; + break; + case HEADER_PROXY: +- h[0] = data->set.headers; ++ h[0] = noproxyheaders; + if(data->set.sep_headers) { + h[1] = data->set.proxyheaders; + numlists++; +@@ -1475,12 +1485,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, + if(data->set.sep_headers) + h[0] = data->set.proxyheaders; + else +- h[0] = data->set.headers; ++ h[0] = noproxyheaders; + break; + } + #else + (void)is_connect; +- h[0] = data->set.headers; ++ h[0] = noproxyheaders; + #endif -@@ -14,39 +19,74 @@ + /* loop through one or two lists */ +@@ -1717,6 +1727,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, + *reqp = httpreq; + } - - URL RFC 3986 syntax - - custom maximum download time -- - custom least download speed acceptable -+ - custom lowest download speed acceptable - - custom output result after completion - - guesses protocol from hostname unless specified -- - uses .netrc -+ - supports .netrc - - progress bar with time statistics while downloading -- - "standard" proxy environment variables support -- - compiles on win32 (reported builds on 70+ operating systems) -+ - standard proxy environment variables support -+ - have run on 101 operating systems and 28 CPU architectures - - selectable network interface for outgoing traffic - - IPv6 support on Unix and Windows -- - happy eyeballs dual-stack connects -+ - happy eyeballs dual-stack IPv4 + IPv6 connects - - persistent connections - - SOCKS 4 + 5 support, with or without local name resolving -+ - *pre-proxy* support, for *proxy chaining* - - supports username and password in proxy environment variables - - operations through HTTP proxy "tunnel" (using CONNECT) - - replaceable memory functions (malloc, free, realloc, etc) -- - asynchronous name resolving (6) -+ - asynchronous name resolving - - both a push and a pull style interface -- - international domain names (10) -+ - international domain names (IDN) -+ - transfer rate limiting -+ - stable API and ABI -+ - TCP keep alive -+ - TCP Fast Open -+ - DNS cache (that can be shared between transfers) -+ - non-blocking single-threaded parallel transfers -+ - Unix domain sockets to server or proxy -+ - DNS-over-HTTPS -+ - uses non-blocking name resolves -+ - selectable name resolver backend ++/* ++ * curl-impersonate: ++ * Create a new linked list of headers. ++ * The new list is a merge between the "base" headers and the application given ++ * headers. The "base" headers contain curl-impersonate's list of headers ++ * used by default by the impersonated browser. ++ * ++ * The application given headers will override the "base" headers if supplied. ++ */ ++CURLcode Curl_http_merge_headers(struct Curl_easy *data) ++{ ++ int i; ++ int ret; ++ struct curl_slist *head; ++ struct curl_slist *dup = NULL; ++ struct curl_slist *new_list = NULL; ++ char *uagent; + -+## URL API ++ if (!data->state.base_headers) ++ return CURLE_OK; + -+ - parses RFC 3986 URLs -+ - generates URLs from individual components -+ - manages "redirects" ++ /* Duplicate the list for temporary use. */ ++ if (data->set.headers) { ++ dup = Curl_slist_duplicate(data->set.headers); ++ if(!dup) ++ return CURLE_OUT_OF_MEMORY; ++ } + -+## Header API ++ for(head = data->state.base_headers; head; head = head->next) { ++ char *sep; ++ size_t prefix_len; ++ bool found = FALSE; ++ struct curl_slist *head2; + -+ - easy access to HTTP response headers, from all contexts -+ - named headers -+ - iterate over headers ++ sep = strchr(head->data, ':'); ++ if(!sep) ++ continue; + -+## TLS ++ prefix_len = sep - head->data; + -+ - selectable TLS backend(s) -+ - TLS False Start -+ - TLS version control -+ - TLS session resumption -+ - key pinning -+ - mutual authentication -+ - Use dedicated CA cert bundle -+ - Use OS-provided CA store -+ - separate TLS options for HTTPS proxy - - ## HTTP - - - HTTP/0.9 responses are optionally accepted - - HTTP/1.0 - - HTTP/1.1 -- - HTTP/2, including multiplexing and server push (5) -+ - HTTP/2, including multiplexing and server push - - GET - - PUT - - HEAD - - POST - - multipart formpost (RFC 1867-style) -- - authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO) (3) -+ - authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO) - to server and proxy -- - resume (both GET and PUT) -+ - resume transfers - - follow redirects - - maximum amount of redirects to follow - - custom HTTP request -@@ -59,26 +99,30 @@ - - proxy authentication - - time conditions - - via HTTP proxy, HTTPS proxy or SOCKS proxy -+ - HTTP/2 or HTTP/1.1 to HTTPS proxy - - retrieve file modification date -- - Content-Encoding support for deflate and gzip -+ - Content-Encoding support for deflate, gzip, brotli and zstd - - "Transfer-Encoding: chunked" support in uploads -- - automatic data compression (11) -+ - HSTS -+ - alt-svc -+ - ETags -+ - HTTP/1.1 trailers, both sending and getting - --## HTTPS (1) -+## HTTPS - -- - (all the HTTP features) -- - HTTP/3 experimental support -+ - HTTP/3 - - using client certificates - - verify server certificate - - via HTTP proxy, HTTPS proxy or SOCKS proxy - - select desired encryption -- - select usage of a specific SSL version -+ - select usage of a specific TLS version -+ - ECH - - ## FTP - - - download - - authentication -- - Kerberos 5 (12) -+ - Kerberos 5 - - active/passive using PORT, EPRT, PASV or EPSV - - single file size information (compare to HTTP HEAD) - - 'type=' URL support -@@ -96,20 +140,24 @@ - - customizable to retrieve file modification date - - no directory depth limit - --## FTPS (1) -+## FTPS - - - implicit `ftps://` support that use SSL on both connections - - explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain `ftp://` - connection to use SSL for both or one of the connections - --## SCP (8) -+## SSH (both SCP and SFTP) - -+ - selectable SSH backend -+ - known hosts support -+ - public key fingerprinting - - both password and public key auth - --## SFTP (7) -+## SFTP - - - both password and public key auth - - with custom commands sent before/after the transfer -+ - directory listing - - ## TFTP - -@@ -122,7 +170,7 @@ - - custom telnet options - - stdin/stdout I/O - --## LDAP (2) -+## LDAP - - - full LDAP URL support - -@@ -145,8 +193,8 @@ - - ## SMTP - -- - authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), Kerberos 5 -- (4) and External. -+ - authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM, Kerberos 5 and -+ External - - send emails - - mail from support - - mail size support -@@ -154,7 +202,7 @@ - - multiple recipients - - via http-proxy - --## SMTPS (1) -+## SMTPS - - - implicit `smtps://` support - - explicit "STARTTLS" usage to "upgrade" plain `smtp://` connections to use SSL -@@ -163,15 +211,15 @@ - ## POP3 - - - authentication: Clear Text, APOP and SASL -- - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), -- Kerberos 5 (4) and External. -+ - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM, -+ Kerberos 5 and External - - list emails - - retrieve emails - - enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via - custom requests - - via http-proxy - --## POP3S (1) -+## POP3S - - - implicit `pop3s://` support - - explicit `STLS` usage to "upgrade" plain `pop3://` connections to use SSL -@@ -180,8 +228,8 @@ - ## IMAP - - - authentication: Clear Text and SASL -- - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), -- Kerberos 5 (4) and External. -+ - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM, -+ Kerberos 5 and External - - list the folders of a mailbox - - select a mailbox with support for verifying the `UIDVALIDITY` - - fetch emails with support for specifying the UID and SECTION -@@ -190,7 +238,7 @@ - STORE, COPY and UID via custom requests - - via http-proxy - --## IMAPS (1) -+## IMAPS - - - implicit `imaps://` support - - explicit "STARTTLS" usage to "upgrade" plain `imap://` connections to use SSL -@@ -199,21 +247,3 @@ - ## MQTT - - - Subscribe to and publish topics using URL scheme `mqtt://broker/topic` -- --## Footnotes -- -- 1. requires a TLS library -- 2. requires OpenLDAP or WinLDAP -- 3. requires a GSS-API implementation (such as Heimdal or MIT Kerberos) or -- SSPI (native Windows) -- 4. requires a GSS-API implementation, however, only Windows SSPI is -- currently supported -- 5. requires nghttp2 -- 6. requires c-ares -- 7. requires libssh2, libssh or wolfSSH -- 8. requires libssh2 or libssh -- 9. requires OpenSSL, GnuTLS, mbedTLS, Secure Transport or SSPI -- (native Windows) -- 10. requires libidn2 or Windows -- 11. requires libz, brotli and/or zstd -- 12. requires a GSS-API implementation (such as Heimdal or MIT Kerberos) -diff --git a/docs/GOVERNANCE.md b/docs/GOVERNANCE.md -index 09723c4d0..4ab52a9a0 100644 ---- a/docs/GOVERNANCE.md -+++ b/docs/GOVERNANCE.md -@@ -1,3 +1,9 @@ -+ ++ /* Check if this header was added by the application. */ ++ for(head2 = dup; head2; head2 = head2->next) { ++ if(head2->data && ++ strncasecompare(head2->data, head->data, prefix_len) && ++ Curl_headersep(head2->data[prefix_len]) ) { ++ new_list = curl_slist_append(new_list, head2->data); ++ /* Free and set to NULL to mark that it's been added. */ ++ Curl_safefree(head2->data); ++ found = TRUE; ++ break; ++ } ++ } + - # Decision making in the curl project - - A rough guide to how we make decisions and who does what. -diff --git a/docs/HELP-US.md b/docs/HELP-US.md -index 15996d046..0619aec53 100644 ---- a/docs/HELP-US.md -+++ b/docs/HELP-US.md -@@ -1,3 +1,9 @@ -+ ++ if (!found) { ++ new_list = curl_slist_append(new_list, head->data); ++ } + - # How to get started helping out in the curl project - - We are always in need of more help. If you are new to the project and are -diff --git a/docs/HISTORY.md b/docs/HISTORY.md -index d28217ca6..0ec3cd159 100644 ---- a/docs/HISTORY.md -+++ b/docs/HISTORY.md -@@ -1,3 +1,9 @@ -+ ++ /* Now go over any additional application-supplied headers. */ ++ for(head = dup; head; head = head->next) { ++ if(head->data) { ++ new_list = curl_slist_append(new_list, head->data); ++ if(!new_list) { ++ ret = CURLE_OUT_OF_MEMORY; ++ goto fail; ++ } ++ } ++ } + - How curl Became Like This - ========================= - -@@ -280,7 +286,7 @@ August: - - February: added support for the axTLS backend - --April: added the cyassl backend (later renamed to WolfSSL) -+April: added the cyassl backend (later renamed to wolfSSL) - - 2012 - ---- -@@ -413,14 +419,14 @@ April: added the cyassl backend (later renamed to WolfSSL) - - February 3: curl 7.75.0 ships with support for Hyper as an HTTP backend - -- March 31: curl 7.76.0 ships with support for rustls -+ March 31: curl 7.76.0 ships with support for Rustls - - July: HSTS is supported - - 2022 - ---- - -- March: added --json, removed mesalink support -+March: added --json, removed mesalink support - - Public curl releases: 206 - Command line options: 245 -@@ -431,7 +437,34 @@ April: added the cyassl backend (later renamed to WolfSSL) - The curl.se website serves 16,500 GB/month over 462M requests, the - official docker image has been pulled 4,098,015,431 times. - -+October: initial WebSocket support ++ curl_slist_free_all(dup); ++ /* Save the new, merged list separately, so it can be freed later. */ ++ curl_slist_free_all(data->state.merged_headers); ++ data->state.merged_headers = new_list; + - 2023 - ---- - -+March: remove support for curl_off_t < 8 bytes ++ return CURLE_OK; + -+March 31: we started working on a new command line tool for URL parsing and -+manipulations: trurl. ++fail: ++ Curl_safefree(dup); ++ curl_slist_free_all(new_list); ++ return ret; ++} + -+May: added support for HTTP/2 over HTTPS proxy. Refuse to resolve .onion. + CURLcode Curl_http_useragent(struct Curl_easy *data) + { + /* The User-Agent string might have been allocated in url.c already, because +@@ -2558,6 +2670,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) + if(result) + goto fail; + ++ /* curl-impersonate: Add HTTP headers to impersonate real browsers. */ ++ result = Curl_http_merge_headers(data); ++ if (result) ++ return result; + - August: Dropped support for the NSS library + result = Curl_http_host(data, conn); + if(result) + goto fail; +@@ -4269,12 +4386,41 @@ static bool h2_non_field(const char *name, size_t namelen) + return FALSE; + } + ++/* ++ * curl-impersonate: ++ * Determine the position of HTTP/2 pseudo headers. ++ * The pseudo headers ":method", ":path", ":scheme", ":authority" ++ * are sent in different order by different browsers. An important part of the ++ * impersonation is ordering them like the browser does. ++ */ ++static CURLcode h2_check_pseudo_header_order(const char *order) ++{ ++ if(strlen(order) != 4) ++ return CURLE_BAD_FUNCTION_ARGUMENT; + -+September: added "variable" support in the command line tool. Dropped support -+for the gskit TLS library. ++ // :method should always be first ++ if(order[0] != 'm') ++ return CURLE_BAD_FUNCTION_ARGUMENT; + -+October: added support for IPFS via HTTP gateway ++ // All pseudo-headers must be present ++ if(!strchr(order, 'm') || ++ !strchr(order, 'a') || ++ !strchr(order, 's') || ++ !strchr(order, 'p')) ++ return CURLE_BAD_FUNCTION_ARGUMENT; + -+December: HTTP/3 support with ngtcp2 is no longer experimental ++ return CURLE_OK; ++} + -+2024 -+---- + CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + struct httpreq *req, struct Curl_easy *data) + { + const char *scheme = NULL, *authority = NULL; + struct dynhds_entry *e; + size_t i; ++ // Use the Chrome ordering by default: ++ // :method, :authority, :scheme, :path ++ char *order = "masp"; + CURLcode result; + + DEBUGASSERT(req); +@@ -4308,25 +4454,56 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, + + Curl_dynhds_reset(h2_headers); + Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), +- req->method, strlen(req->method)); +- if(!result && scheme) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), +- scheme, strlen(scheme)); +- } +- if(!result && authority) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), +- authority, strlen(authority)); + -+January: switched to "curldown" for all documentation ++ /* curl-impersonate: order of pseudo headers is different from the default */ ++ if(data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]) { ++ order = data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]; + } +- if(!result && req->path) { +- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), +- req->path, strlen(req->path)); + -+April 24: the curl container has been pulled more than six billion times ++ result = h2_check_pseudo_header_order(order); + -+May: experimental support for ECH ++ /* curl-impersonate: add http2 pseudo headers according to the specified order. */ ++ for(i = 0; !result && i < strlen(order); ++i) { ++ switch(order[i]) { ++ case 'm': ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), ++ req->method, strlen(req->method)); ++ break; ++ case 'a': ++ if(authority) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), ++ authority, strlen(authority)); ++ } ++ break; ++ case 's': ++ if(scheme) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), ++ scheme, strlen(scheme)); ++ } ++ break; ++ case 'p': ++ if(req->path) { ++ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), ++ req->path, strlen(req->path)); ++ } ++ break; ++ } + } + -+August 9: we adopted the wcurl tool into the curl organization -diff --git a/docs/HTTP-COOKIES.md b/docs/HTTP-COOKIES.md -index 174c4f536..38432d273 100644 ---- a/docs/HTTP-COOKIES.md -+++ b/docs/HTTP-COOKIES.md -@@ -1,3 +1,9 @@ -+ + result = Curl_dynhds_add(h2_headers, e->name, e->namelen, + e->value, e->valuelen); + - # HTTP Cookies ++ Curl_dynhds_del_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); + } + } - ## Cookie overview -diff --git a/docs/HTTP3.md b/docs/HTTP3.md -index 783ab101f..3ff73c8e5 100644 ---- a/docs/HTTP3.md -+++ b/docs/HTTP3.md -@@ -1,3 +1,9 @@ -+ -+ - # HTTP3 (and QUIC) +diff --git a/lib/http2.c b/lib/http2.c +index 99d7f3b0e..88419cfca 100644 +--- a/lib/http2.c ++++ b/lib/http2.c +@@ -51,6 +51,7 @@ + #include "curl_printf.h" + #include "curl_memory.h" + #include "memdebug.h" ++#include "rand.h" - ## Resources -@@ -45,7 +51,7 @@ Building curl with ngtcp2 involves 3 components: `ngtcp2` itself, `nghttp3` and - OpenSSL does not offer the required APIs for building a QUIC client. You need - to use a TLS library that has such APIs and that works with *ngtcp2*. + #if (NGHTTP2_VERSION_NUM < 0x010c00) + #error too old nghttp2 version, upgrade! +@@ -69,7 +70,7 @@ + * use 16K as chunk size, as that fits H2 DATA frames well */ + #define H2_CHUNK_SIZE (16 * 1024) + /* this is how much we want "in flight" for a stream */ +-#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024) ++#define H2_STREAM_WINDOW_SIZE (1024 * 1024) + /* on receiving from TLS, we prep for holding a full stream window */ + #define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) + /* on send into TLS, we just want to accumulate small frames */ +@@ -87,26 +88,99 @@ + * will block their received QUOTA in the connection window. And if we + * run out of space, the server is blocked from sending us any data. + * See #10988 for an issue with this. */ +-#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE) ++/* curl-impersonate: match Chrome window size. */ ++#define HTTP2_HUGE_WINDOW_SIZE (15 * H2_STREAM_WINDOW_SIZE) --Build quictls -+Build quictls: +-#define H2_SETTINGS_IV_LEN 3 ++#define H2_SETTINGS_IV_LEN 8 + #define H2_BINSETTINGS_LEN 80 - % git clone --depth 1 -b openssl-3.1.4+quic https://github.com/quictls/openssl - % cd openssl -@@ -53,7 +59,7 @@ Build quictls - % make - % make install ++ + static int populate_settings(nghttp2_settings_entry *iv, + struct Curl_easy *data) + { +- iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; +- iv[0].value = Curl_multi_max_concurrent_streams(data->multi); ++ // curl-impersonate: ++ // Setting http2 settings frame based on user instruction. ++ // https://httpwg.org/specs/rfc7540.html#SETTINGS ++ // Format example: 1:65536;2:0;4:6291456;6:262144 ++ ++ // TODO check if the http2 settings is valid ++ int i = 0; ++ char *delimiter = ";"; ++ ++ // Use chrome's settings as default ++ char *http2_settings = "1:65536;2:0;4:6291456;6:262144"; ++ if(data->set.str[STRING_HTTP2_SETTINGS]) { ++ http2_settings = data->set.str[STRING_HTTP2_SETTINGS]; ++ } --Build nghttp3 -+Build nghttp3: - - % cd .. - % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 -@@ -64,7 +70,7 @@ Build nghttp3 - % make - % make install - --Build ngtcp2 -+Build ngtcp2: - - % cd .. - % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 -@@ -74,7 +80,7 @@ Build ngtcp2 - % make - % make install - --Build curl -+Build curl: - - % cd .. - % git clone https://github.com/curl/curl -@@ -88,7 +94,7 @@ For OpenSSL 3.0.0 or later builds on Linux for x86_64 architecture, substitute a - - ## Build with GnuTLS - --Build GnuTLS -+Build GnuTLS: - - % git clone --depth 1 https://gitlab.com/gnutls/gnutls.git - % cd gnutls -@@ -97,7 +103,7 @@ Build GnuTLS - % make - % make install - --Build nghttp3 -+Build nghttp3: - - % cd .. - % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 -@@ -108,7 +114,7 @@ Build nghttp3 - % make - % make install - --Build ngtcp2 -+Build ngtcp2: - - % cd .. - % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 -@@ -118,7 +124,7 @@ Build ngtcp2 - % make - % make install - --Build curl -+Build curl: - - % cd .. - % git clone https://github.com/curl/curl -@@ -130,7 +136,7 @@ Build curl - - ## Build with wolfSSL - --Build wolfSSL -+Build wolfSSL: - - % git clone https://github.com/wolfSSL/wolfssl.git - % cd wolfssl -@@ -139,7 +145,7 @@ Build wolfSSL - % make - % make install - --Build nghttp3 -+Build nghttp3: - - % cd .. - % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 -@@ -150,7 +156,7 @@ Build nghttp3 - % make - % make install - --Build ngtcp2 -+Build ngtcp2: - - % cd .. - % git clone -b v1.2.0 https://github.com/ngtcp2/ngtcp2 -@@ -160,7 +166,7 @@ Build ngtcp2 - % make - % make install - --Build curl -+Build curl: - - % cd .. - % git clone https://github.com/curl/curl -@@ -176,13 +182,14 @@ quiche support is **EXPERIMENTAL** - - Since the quiche build manages its dependencies, curl can be built against the latest version. You are *probably* able to build against their main branch, but in case of problems, we recommend their latest release tag. - --## build -+## Build - - Build quiche and BoringSSL: - -- % git clone --recursive -b 0.20.0 https://github.com/cloudflare/quiche -+ % git clone --recursive -b 0.22.0 https://github.com/cloudflare/quiche - % cd quiche - % cargo build --package quiche --release --features ffi,pkg-config-meta,qlog -+ % ln -s libquiche.so target/release/libquiche.so.0 - % mkdir quiche/deps/boringssl/src/lib - % ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/ - -@@ -203,16 +210,16 @@ Build curl: - - QUIC support is **EXPERIMENTAL** - --Build OpenSSL 3.2.0 -+Build OpenSSL 3.3.1: - - % cd .. -- % git clone -b openssl-3.2.0 https://github.com/openssl/openssl -+ % git clone -b openssl-3.3.1 https://github.com/openssl/openssl - % cd openssl -- % ./config enable-tls1_3 --prefix= --libdir=/lib -+ % ./config enable-tls1_3 --prefix= --libdir=lib - % make - % make install - --Build nghttp3 -+Build nghttp3: - - % cd .. - % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3 -@@ -229,7 +236,7 @@ Build curl: - % git clone https://github.com/curl/curl - % cd curl - % autoreconf -fi -- % LDFLAGS="-Wl,-rpath,/lib" ./configure --with-openssl= --with-openssl-quic --with-nghttp3= -+ % LDFLAGS="-Wl,-rpath,/lib" ./configure --with-openssl= --with-openssl-quic --with-nghttp3= - % make - % make install - -@@ -238,9 +245,9 @@ You can build curl with cmake: - % cd .. - % git clone https://github.com/curl/curl - % cd curl -- % cmake . -B build -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON -- % cmake --build build -- % cmake --install build -+ % cmake . -B bld -DCURL_USE_OPENSSL=ON -DUSE_OPENSSL_QUIC=ON -+ % cmake --build bld -+ % cmake --install bld - - If `make install` results in `Permission denied` error, you need to prepend - it with `sudo`. -@@ -310,15 +317,15 @@ directory, or copy `msquic.dll` and `msh3.dll` from that directory to the - - Use only HTTP/3: - -- curl --http3-only https://example.org:4433/ -+ % curl --http3-only https://example.org:4433/ - - Use HTTP/3 with fallback to HTTP/2 or HTTP/1.1 (see "HTTPS eyeballing" below): - -- curl --http3 https://example.org:4433/ -+ % curl --http3 https://example.org:4433/ - - Upgrade via Alt-Svc: - -- curl --alt-svc altsvc.cache https://curl.se/ -+ % curl --alt-svc altsvc.cache https://curl.se/ - - See this [list of public HTTP/3 servers](https://bagder.github.io/HTTP3-test/) - -@@ -376,7 +383,7 @@ ones. You can easily create huge local files like `truncate -s=8G 8GB` - they - are huge but do not occupy that much space on disk since they are just big - holes. - --In a Debian setup you can install **apache2**. It runs on port 80 and has a -+In a Debian setup you can install apache2. It runs on port 80 and has a - document root in `/var/www/html`. Download the 8GB file from apache with `curl - localhost/8GB -o dev/null` - -@@ -389,23 +396,23 @@ You can select either or both of these server solutions. - - ### nghttpx - --Get, build and install **quictls**, **nghttp3** and **ngtcp2** as described -+Get, build and install quictls, nghttp3 and ngtcp2 as described - above. - --Get, build and install **nghttp2**: -+Get, build and install nghttp2: - -- git clone https://github.com/nghttp2/nghttp2.git -- cd nghttp2 -- autoreconf -fi -- PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/daniel/build-quictls/lib/pkgconfig:/home/daniel/build-nghttp3/lib/pkgconfig:/home/daniel/build-ngtcp2/lib/pkgconfig LDFLAGS=-L/home/daniel/build-quictls/lib CFLAGS=-I/home/daniel/build-quictls/include ./configure --enable-maintainer-mode --prefix=/home/daniel/build-nghttp2 --disable-shared --enable-app --enable-http3 --without-jemalloc --without-libxml2 --without-systemd -- make && make install -+ % git clone https://github.com/nghttp2/nghttp2.git -+ % cd nghttp2 -+ % autoreconf -fi -+ % PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/daniel/build-quictls/lib/pkgconfig:/home/daniel/build-nghttp3/lib/pkgconfig:/home/daniel/build-ngtcp2/lib/pkgconfig LDFLAGS=-L/home/daniel/build-quictls/lib CFLAGS=-I/home/daniel/build-quictls/include ./configure --enable-maintainer-mode --prefix=/home/daniel/build-nghttp2 --disable-shared --enable-app --enable-http3 --without-jemalloc --without-libxml2 --without-systemd -+ % make && make install - - Run the local h3 server on port 9443, make it proxy all traffic through to - HTTP/1 on localhost port 80. For local toying, we can just use the test cert - that exists in curl's test dir. - -- CERT=$CURLSRC/tests/stunnel.pem -- $HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \ -+ % CERT=$CURLSRC/tests/stunnel.pem -+ % $HOME/bin/nghttpx $CERT $CERT --backend=localhost,80 \ - --frontend="localhost,9443;quic" - - ### Caddy -@@ -422,7 +429,7 @@ localhost:7443 { - - Then run Caddy: - -- ./caddy start -+ % ./caddy start - - Making requests to `https://localhost:7443` should tell you which protocol is being used. - -diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md -index a606fcb21..a74e1930e 100644 ---- a/docs/INSTALL-CMAKE.md -+++ b/docs/INSTALL-CMAKE.md -@@ -1,10 +1,8 @@ -- _ _ ____ _ -- ___| | | | _ \| | -- / __| | | | |_) | | -- | (__| |_| | _ <| |___ -- \___|\___/|_| \_\_____| -+ - - # Building with CMake - -@@ -18,23 +16,6 @@ instructions below for the platform you are building on. - CMake builds can be configured either from the command line, or from one of - CMake's GUIs. - --# Current flaws in the curl CMake build -- --Missing features in the CMake build: -- -- - Builds libcurl without large file support -- - Does not support all SSL libraries (only OpenSSL, Schannel, Secure -- Transport, and mbedTLS, WolfSSL) -- - Does not allow different resolver backends (no c-ares build support) -- - No RTMP support built -- - Does not allow build curl and libcurl debug enabled -- - Does not allow a custom CA bundle path -- - Does not allow you to disable specific protocols from the build -- - Does not find or use krb4 or GSS -- - Rebuilds test files too eagerly, but still cannot run the tests -- - Does not detect the correct `strerror_r` flavor when cross-compiling -- (issue #1123) -- - # Configuring - - A CMake configuration of curl is similar to the autotools build of curl. -@@ -68,6 +49,13 @@ If you want to build in the source tree, it is enough to do this: - - $ cmake . - -+### Build system generator selection +- iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; +- iv[1].value = H2_STREAM_WINDOW_SIZE; ++ // printf("USING settings %s\n", http2_settings); + -+You can override CMake's default by using `-G `. For example -+on Windows with multiple build systems if you have MinGW-w64 then you could use -+`-G "MinGW Makefiles"`. -+[List of generator names](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html). ++ char *tmp = strdup(http2_settings); ++ char *setting = strtok(tmp, delimiter); + - ## Using `ccmake` ++ // loop through the string to extract all other tokens ++ while(setting != NULL) { ++ // deal with each setting ++ switch(setting[0]) { ++ case '1': ++ iv[i].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ case '2': ++ iv[i].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ case '3': ++ // FIXME We also need to notify curl_multi about this setting ++ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ case '4': ++ iv[i].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ case '5': ++ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ case '6': ++ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ // https://tools.ietf.org/html/rfc8441 ++ case '8': ++ iv[i].settings_id = NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ // https://tools.ietf.org/html/rfc9218 ++ case '9': ++ iv[i].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES; ++ iv[i].value = atoi(setting + 2); ++ i++; ++ break; ++ } ++ setting = strtok(NULL, delimiter); ++ } ++ free(tmp); - CMake comes with a curses based interface called `ccmake`. To run `ccmake` -@@ -102,6 +90,25 @@ Build (you have to specify the build directory). +- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; +- iv[2].value = data->multi->push_cb != NULL; ++ // curl-impersonate: ++ // Up until Chrome 98, there was a randomly chosen setting number in the ++ // HTTP2 SETTINGS frame. This might be something similar to TLS GREASE. ++ // However, it seems to have been removed since. ++ // Curl_rand(data, (unsigned char *)&iv[4].settings_id, sizeof(iv[4].settings_id)); ++ // Curl_rand(data, (unsigned char *)&iv[4].value, sizeof(iv[4].value)); - $ cmake --build ../curl-build +- return 3; ++ return i; + } -+## Static builds -+ -+The CMake build setup is primarily done to work with shared/dynamic third -+party dependencies. When linking with shared libraries, the dependency "chain" -+is handled automatically by the library loader - on all modern systems. -+ -+If you instead link with a static library, you need to provide all the -+dependency libraries already at the link command line. + -+Figuring out all the dependency libraries for a given library is hard, as it -+might involve figuring out the dependencies of the dependencies and they vary -+between platforms and can change between versions. -+ -+When using static dependencies, the build scripts mostly assume that you, the -+user, provide all the necessary additional dependency libraries as additional -+arguments in the build. -+ -+Building statically is not for the faint of heart. -+ - ### Fallback for CMake before version 3.13 - - CMake before version 3.13 does not support the `--build` option. In that -@@ -131,3 +138,226 @@ assumes that CMake generates `Makefile`: + static ssize_t populate_binsettings(uint8_t *binsettings, + struct Curl_easy *data) + { +@@ -165,6 +239,75 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) + } + } - $ cd ../curl-build - $ make install -+ -+# CMake build options -+ -+- `BUILD_CURL_EXE`: Build curl executable. Default: `ON` -+- `BUILD_EXAMPLES`: Build libcurl examples. Default: `ON` -+- `BUILD_LIBCURL_DOCS`: Build libcurl man pages. Default: `ON` -+- `BUILD_MISC_DOCS`: Build misc man pages (e.g. `curl-config` and `mk-ca-bundle`). Default: `ON` -+- `BUILD_SHARED_LIBS`: Build shared libraries. Default: `ON` -+- `BUILD_STATIC_CURL`: Build curl executable with static libcurl. Default: `OFF` -+- `BUILD_STATIC_LIBS`: Build static libraries. Default: `OFF` -+- `BUILD_TESTING`: Build tests. Default: `ON` -+- `CURL_DEFAULT_SSL_BACKEND`: Override default TLS backend in MultiSSL builds. -+ Accepted values in order of default priority: -+ `wolfssl`, `gnutls`, `mbedtls`, `openssl`, `secure-transport`, `schannel`, `bearssl`, `rustls` -+- `CURL_ENABLE_EXPORT_TARGET`: Enable CMake export target. Default: `ON` -+- `CURL_HIDDEN_SYMBOLS`: Hide libcurl internal symbols (=hide all symbols that are not officially external). Default: `ON` -+- `CURL_LIBCURL_SOVERSION`: Enable libcurl SOVERSION. Default: `ON` for supported platforms -+- `CURL_LIBCURL_VERSIONED_SYMBOLS`: Enable libcurl versioned symbols. Default: `OFF` -+- `CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX`: Override default versioned symbol prefix. Default: `_` or `MULTISSL_` -+- `CURL_LTO`: Enable compiler Link Time Optimizations. Default: `OFF` -+- `CURL_STATIC_CRT`: Build libcurl with static CRT with MSVC (`/MT`). Default: `OFF` -+- `CURL_TARGET_WINDOWS_VERSION`: Minimum target Windows version as hex string. -+- `CURL_TEST_BUNDLES`: Bundle `libtest` and `unittest` tests into single binaries. Default: `OFF` -+- `CURL_WERROR`: Turn compiler warnings into errors. Default: `OFF` -+- `ENABLE_CURLDEBUG`: Enable TrackMemory debug feature: Default: =`ENABLE_DEBUG` -+- `ENABLE_CURL_MANUAL`: Build the man page for curl and enable its `-M`/`--manual` option. Default: `ON` -+- `ENABLE_DEBUG`: Enable curl debug features (for developing curl itself). Default: `OFF` -+- `IMPORT_LIB_SUFFIX`: Import library suffix. Default: `_imp` -+- `LIBCURL_OUTPUT_NAME`: Basename of the curl library. Default: `libcurl` -+- `PICKY_COMPILER`: Enable picky compiler options. Default: `ON` -+- `STATIC_LIB_SUFFIX`: Static library suffix. Default: (empty) -+ -+## CA bundle options -+ -+- `CURL_CA_BUNDLE`: Path to the CA bundle. Set `none` to disable or `auto` for auto-detection. Default: `auto` -+- `CURL_CA_EMBED`: Path to the CA bundle to embed in the curl tool. Default: (disabled) -+- `CURL_CA_FALLBACK`: Use built-in CA store of TLS backend. Default: `OFF` -+- `CURL_CA_PATH`: Location of default CA path. Set `none` to disable or `auto` for auto-detection. Default: `auto` -+- `CURL_CA_SEARCH_SAFE`: Enable safe CA bundle search (within the curl tool directory) on Windows. Default: `OFF` -+ -+## Enabling features -+ -+- `CURL_ENABLE_SSL`: Enable SSL support. Default: `ON` -+- `CURL_WINDOWS_SSPI`: Enable SSPI on Windows. Default: =`CURL_USE_SCHANNEL` -+- `ENABLE_IPV6`: Enable IPv6 support. Default: `ON` -+- `ENABLE_THREADED_RESOLVER`: Enable threaded DNS lookup. Default: `ON` if c-ares is not enabled -+- `ENABLE_UNICODE`: Use the Unicode version of the Windows API functions. Default: `OFF` -+- `ENABLE_UNIX_SOCKETS`: Enable Unix domain sockets support. Default: `ON` -+- `USE_ECH`: Enable ECH support. Default: `OFF` -+- `USE_HTTPSRR`: Enable HTTPS RR support for ECH (experimental). Default: `OFF` -+- `USE_OPENSSL_QUIC`: Use OpenSSL and nghttp3 libraries for HTTP/3 support. Default: `OFF` -+ -+## Disabling features -+ -+- `CURL_DISABLE_ALTSVC`: Disable alt-svc support. Default: `OFF` -+- `CURL_DISABLE_AWS`: Disable **aws-sigv4**. Default: `OFF` -+- `CURL_DISABLE_BASIC_AUTH`: Disable Basic authentication. Default: `OFF` -+- `CURL_DISABLE_BEARER_AUTH`: Disable Bearer authentication. Default: `OFF` -+- `CURL_DISABLE_BINDLOCAL`: Disable local binding support. Default: `OFF` -+- `CURL_DISABLE_CA_SEARCH`: Disable unsafe CA bundle search in PATH on Windows. Default: `OFF` -+- `CURL_DISABLE_COOKIES`: Disable cookies support. Default: `OFF` -+- `CURL_DISABLE_DICT`: Disable DICT. Default: `OFF` -+- `CURL_DISABLE_DIGEST_AUTH`: Disable Digest authentication. Default: `OFF` -+- `CURL_DISABLE_DOH`: Disable DNS-over-HTTPS. Default: `OFF` -+- `CURL_DISABLE_FILE`: Disable FILE. Default: `OFF` -+- `CURL_DISABLE_FORM_API`: Disable **form-api**: Default: =`CURL_DISABLE_MIME` -+- `CURL_DISABLE_FTP`: Disable FTP. Default: `OFF` -+- `CURL_DISABLE_GETOPTIONS`: Disable `curl_easy_options` API for existing options to `curl_easy_setopt`. Default: `OFF` -+- `CURL_DISABLE_GOPHER`: Disable Gopher. Default: `OFF` -+- `CURL_DISABLE_HEADERS_API`: Disable **headers-api** support. Default: `OFF` -+- `CURL_DISABLE_HSTS`: Disable HSTS support. Default: `OFF` -+- `CURL_DISABLE_HTTP`: Disable HTTP. Default: `OFF` -+- `CURL_DISABLE_HTTP_AUTH`: Disable all HTTP authentication methods. Default: `OFF` -+- `CURL_DISABLE_IMAP`: Disable IMAP. Default: `OFF` -+- `CURL_DISABLE_INSTALL`: Disable installation targets. Default: `OFF` -+- `CURL_DISABLE_IPFS`: Disable IPFS. Default: `OFF` -+- `CURL_DISABLE_KERBEROS_AUTH`: Disable Kerberos authentication. Default: `OFF` -+- `CURL_DISABLE_LDAP`: Disable LDAP. Default: `OFF` -+- `CURL_DISABLE_LDAPS`: Disable LDAPS. Default: =`CURL_DISABLE_LDAP` -+- `CURL_DISABLE_LIBCURL_OPTION`: Disable `--libcurl` option from the curl tool. Default: `OFF` -+- `CURL_DISABLE_MIME`: Disable MIME support. Default: `OFF` -+- `CURL_DISABLE_MQTT`: Disable MQTT. Default: `OFF` -+- `CURL_DISABLE_NEGOTIATE_AUTH`: Disable negotiate authentication. Default: `OFF` -+- `CURL_DISABLE_NETRC`: Disable netrc parser. Default: `OFF` -+- `CURL_DISABLE_NTLM`: Disable NTLM support. Default: `OFF` -+- `CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG`: Disable automatic loading of OpenSSL configuration. Default: `OFF` -+- `CURL_DISABLE_PARSEDATE`: Disable date parsing. Default: `OFF` -+- `CURL_DISABLE_POP3`: Disable POP3. Default: `OFF` -+- `CURL_DISABLE_PROGRESS_METER`: Disable built-in progress meter. Default: `OFF` -+- `CURL_DISABLE_PROXY`: Disable proxy support. Default: `OFF` -+- `CURL_DISABLE_RTSP`: Disable RTSP. Default: `OFF` -+- `CURL_DISABLE_SHA512_256`: Disable SHA-512/256 hash algorithm. Default: `OFF` -+- `CURL_DISABLE_SHUFFLE_DNS`: Disable shuffle DNS feature. Default: `OFF` -+- `CURL_DISABLE_SMB`: Disable SMB. Default: `OFF` -+- `CURL_DISABLE_SMTP`: Disable SMTP. Default: `OFF` -+- `CURL_DISABLE_SOCKETPAIR`: Disable use of socketpair for curl_multi_poll. Default: `OFF` -+- `CURL_DISABLE_SRP`: Disable TLS-SRP support. Default: `OFF` -+- `CURL_DISABLE_TELNET`: Disable Telnet. Default: `OFF` -+- `CURL_DISABLE_TFTP`: Disable TFTP. Default: `OFF` -+- `CURL_DISABLE_VERBOSE_STRINGS`: Disable verbose strings. Default: `OFF` -+- `CURL_DISABLE_WEBSOCKETS`: Disable WebSocket. Default: `OFF` -+- `HTTP_ONLY`: Disable all protocols except HTTP (This overrides all `CURL_DISABLE_*` options). Default: `OFF` -+ -+## Environment -+ -+- `CI`: Assume running under CI if set. -+- `CURL_BUILDINFO`: Print `buildinfo.txt` if set. -+- `CURL_CI`: Assume running under CI if set. ++static CURLcode http2_set_stream_priority(struct Curl_cfilter *cf, ++ struct Curl_easy *data, ++ int32_t stream_id, ++ int32_t dep_stream_id, ++ int32_t weight, ++ int exclusive ++ ) ++{ ++ int rv; ++ struct cf_h2_ctx *ctx = cf->ctx; ++ nghttp2_priority_spec pri_spec; + -+## CMake options ++ nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive); ++ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, ++ stream_id, &pri_spec); ++ if(rv) { ++ failf(data, "nghttp2_submit_priority() failed: %s(%d)", ++ nghttp2_strerror(rv), rv); ++ return CURLE_HTTP2; ++ } + -+- `CMAKE_DEBUG_POSTFIX`: Default: `-d` -+- `CMAKE_IMPORT_LIBRARY_SUFFIX` (see CMake) -+- `CMAKE_INSTALL_BINDIR` (see CMake) -+- `CMAKE_INSTALL_INCLUDEDIR` (see CMake) -+- `CMAKE_INSTALL_LIBDIR` (see CMake) -+- `CMAKE_INSTALL_PREFIX` (see CMake) -+- `CMAKE_STATIC_LIBRARY_SUFFIX` (see CMake) -+- `CMAKE_UNITY_BUILD_BATCH_SIZE`: Set the number of sources in a "unity" unit. Default: `0` (all) -+- `CMAKE_UNITY_BUILD`: Enable "unity" (aka jumbo) builds. Default: `OFF` ++ return CURLE_OK; ++} + -+Details via CMake -+[variables](https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html) and -+[install directories](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html). ++/* ++ * curl-impersonate: Firefox uses an elaborate scheme of http/2 streams to ++ * split the load for html/js/css/images. It builds a tree of streams with ++ * different weights (priorities) by default and communicates this to the ++ * server. Imitate that behavior. ++ */ ++static CURLcode http2_set_stream_priorities(struct Curl_cfilter *cf, ++ struct Curl_easy *data) ++{ ++ CURLcode result; ++ char *stream_delimiter = ","; ++ char *value_delimiter = ":"; + -+## Dependencies ++ if(!data->set.str[STRING_HTTP2_STREAMS]) ++ return CURLE_OK; + -+- `CURL_BROTLI`: Use brotli. Default: `OFF` -+- `CURL_USE_BEARSSL`: Enable BearSSL for SSL/TLS. Default: `OFF` -+- `CURL_USE_GNUTLS`: Enable GnuTLS for SSL/TLS. Default: `OFF` -+- `CURL_USE_GSASL`: Use libgsasl. Default: `OFF` -+- `CURL_USE_GSSAPI`: Use GSSAPI implementation. Default: `OFF` -+- `CURL_USE_LIBPSL`: Use libpsl. Default: `ON` -+- `CURL_USE_LIBSSH2`: Use libssh2. Default: `ON` -+- `CURL_USE_LIBSSH`: Use libssh. Default: `OFF` -+- `CURL_USE_LIBUV`: Use libuv for event-based tests. Default: `OFF` -+- `CURL_USE_MBEDTLS`: Enable mbedTLS for SSL/TLS. Default: `OFF` -+- `CURL_USE_OPENSSL`: Enable OpenSSL for SSL/TLS. Default: `ON` if no other TLS backend was enabled. -+- `CURL_USE_PKGCONFIG`: Enable `pkg-config` to detect dependencies. Default: `ON` for Unix, vcpkg, MinGW if not cross-compiling. -+- `CURL_USE_RUSTLS`: Enable Rustls for SSL/TLS. Default: `OFF` -+- `CURL_USE_SCHANNEL`: Enable Windows native SSL/TLS (Schannel). Default: `OFF` -+- `CURL_USE_SECTRANSP`: Enable Apple OS native SSL/TLS (Secure Transport). Default: `OFF` -+- `CURL_USE_WOLFSSH`: Use wolfSSH. Default: `OFF` -+- `CURL_USE_WOLFSSL`: Enable wolfSSL for SSL/TLS. Default: `OFF` -+- `CURL_ZLIB`: Use zlib (`ON`, `OFF` or `AUTO`). Default: `AUTO` -+- `CURL_ZSTD`: Use zstd. Default: `OFF` -+- `ENABLE_ARES`: Enable c-ares support. Default: `OFF` -+- `USE_APPLE_IDN`: Use Apple built-in IDN support. Default: `OFF` -+- `USE_LIBIDN2`: Use libidn2 for IDN support. Default: `ON` -+- `USE_LIBRTMP`: Enable librtmp from rtmpdump. Default: `OFF` -+- `USE_MSH3`: Use msh3/msquic library for HTTP/3 support. Default: `OFF` -+- `USE_NGHTTP2`: Use nghttp2 library. Default: `ON` -+- `USE_NGTCP2`: Use ngtcp2 and nghttp3 libraries for HTTP/3 support. Default: `OFF` -+- `USE_QUICHE`: Use quiche library for HTTP/3 support. Default: `OFF` -+- `USE_WIN32_IDN`: Use WinIDN for IDN support. Default: `OFF` -+- `USE_WIN32_LDAP`: Use Windows LDAP implementation. Default: `ON` ++ char *tmp1 = strdup(data->set.str[STRING_HTTP2_STREAMS]); ++ char *end1; ++ char *stream = strtok_r(tmp1, stream_delimiter, &end1); + -+## Dependency options (via CMake) ++ while(stream != NULL) { + -+- `OPENSSL_ROOT_DIR`: Set this variable to the root installation of OpenSSL (and forks). -+- `ZLIB_INCLUDE_DIR`: The zlib include directory. -+- `ZLIB_LIBRARY`: Path to `zlib` library. ++ char *tmp2 = strdup(stream); ++ char *end2; + -+## Dependency options ++ int32_t stream_id = atoi(strtok_r(tmp2, value_delimiter, &end2)); ++ int exclusive = atoi(strtok_r(NULL, value_delimiter, &end2)); ++ int32_t dep_stream_id = atoi(strtok_r(NULL, value_delimiter, &end2)); ++ int32_t weight = atoi(strtok_r(NULL, value_delimiter, &end2)); + -+- `PERL_EXECUTABLE` Perl binary used throughout the build and tests. -+- `BEARSSL_INCLUDE_DIR`: The BearSSL include directory. -+- `BEARSSL_LIBRARY`: Path to `bearssl` library. -+- `BROTLI_INCLUDE_DIR`: The brotli include directory. -+- `BROTLICOMMON_LIBRARY`: Path to `brotlicommon` library. -+- `BROTLIDEC_LIBRARY`: Path to `brotlidec` library. -+- `CARES_INCLUDE_DIR`: The c-ares include directory. -+- `CARES_LIBRARY`: Path to `cares` library. -+- `GSS_ROOT_DIR`: Set this variable to the root installation of GSS. (also supported as environment) -+- `LDAP_LIBRARY`: Name or full path to `ldap` library. Default: `ldap` -+- `LDAP_LBER_LIBRARY`: Name or full path to `lber` library. Default: `lber` -+- `LDAP_INCLUDE_DIR`: Path to LDAP include directory. -+- `LIBGSASL_INCLUDE_DIR`: The libgsasl include directory. -+- `LIBGSASL_LIBRARY`: Path to `libgsasl` library. -+- `LIBIDN2_INCLUDE_DIR`: The libidn2 include directory. -+- `LIBIDN2_LIBRARY`: Path to `libidn2` library. -+- `LIBPSL_INCLUDE_DIR`: The libpsl include directory. -+- `LIBPSL_LIBRARY`: Path to `libpsl` library. -+- `LIBSSH_INCLUDE_DIR`: The libssh include directory. -+- `LIBSSH_LIBRARY`: Path to `libssh` library. -+- `LIBSSH2_INCLUDE_DIR`: The libssh2 include directory. -+- `LIBSSH2_LIBRARY`: Path to `libssh2` library. -+- `LIBUV_INCLUDE_DIR`: The libuv include directory. -+- `LIBUV_LIBRARY`: Path to `libuv` library. -+- `MSH3_INCLUDE_DIR`: The msh3 include directory. -+- `MSH3_LIBRARY`: Path to `msh3` library. -+- `MBEDTLS_INCLUDE_DIR`: The mbedTLS include directory. -+- `MBEDTLS_LIBRARY`: Path to `mbedtls` library. -+- `MBEDX509_LIBRARY`: Path to `mbedx509` library. -+- `MBEDCRYPTO_LIBRARY`: Path to `mbedcrypto` library. -+- `NGHTTP2_INCLUDE_DIR`: The nghttp2 include directory. -+- `NGHTTP2_LIBRARY`: Path to `nghttp2` library. -+- `NGHTTP3_INCLUDE_DIR`: The nghttp3 include directory. -+- `NGHTTP3_LIBRARY`: Path to `nghttp3` library. -+- `NGTCP2_INCLUDE_DIR`: The ngtcp2 include directory. -+- `NGTCP2_LIBRARY`: Path to `ngtcp2` library. -+- `NETTLE_INCLUDE_DIR`: The nettle include directory. -+- `NETTLE_LIBRARY`: Path to `nettle` library. -+- `QUICHE_INCLUDE_DIR`: The quiche include directory. -+- `QUICHE_LIBRARY`: Path to `quiche` library. -+- `RUSTLS_INCLUDE_DIR`: The Rustls include directory. -+- `RUSTLS_LIBRARY`: Path to `rustls` library. -+- `WOLFSSH_INCLUDE_DIR`: The wolfSSH include directory. -+- `WOLFSSH_LIBRARY`: Path to `wolfssh` library. -+- `WOLFSSL_INCLUDE_DIR`: The wolfSSL include directory. -+- `WOLFSSL_LIBRARY`: Path to `wolfssl` library. -+- `ZSTD_INCLUDE_DIR`: The zstd include directory. -+- `ZSTD_LIBRARY`: Path to `zstd` library. ++ free(tmp2); + -+## Test tools ++ result = http2_set_stream_priority(cf, data, stream_id, dep_stream_id, weight, exclusive); ++ if(result) { ++ free(tmp1); ++ return result; ++ } + -+- `APACHECTL`: Default: `apache2ctl` -+- `APXS`: Default: `apxs` -+- `CADDY`: Default: `caddy` -+- `HTTPD_NGHTTPX`: Default: `nghttpx` -+- `HTTPD`: Default: `apache2` -+- `TEST_NGHTTPX`: Default: `nghttpx` -+- `VSFTPD`: Default: `vsftps` -diff --git a/docs/INSTALL.md b/docs/INSTALL.md -index 7971b1aba..bfcbd2e78 100644 ---- a/docs/INSTALL.md -+++ b/docs/INSTALL.md -@@ -1,4 +1,10 @@ --# how to install curl and libcurl -+ ++ free(tmp1); ++ return CURLE_OK; ++} + -+# How to install curl and libcurl - - ## Installing Binary Packages + static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct Curl_easy *data); -@@ -134,7 +140,7 @@ These options are provided to select the TLS backend to use. - - BearSSL: `--with-bearssl` - - GnuTLS: `--with-gnutls`. - - mbedTLS: `--with-mbedtls` -- - OpenSSL: `--with-openssl` (also for BoringSSL, AWS-LC, libressl, and quictls) -+ - OpenSSL: `--with-openssl` (also for BoringSSL, AWS-LC, LibreSSL, and quictls) - - rustls: `--with-rustls` - - Schannel: `--with-schannel` - - Secure Transport: `--with-secure-transport` -@@ -148,7 +154,17 @@ conflicting identical symbol names. - When you build with multiple TLS backends, you can select the active one at - runtime when curl starts up. +@@ -491,8 +634,22 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, + } + } --## configure finding libs in wrong directory -+## MultiSSL and HTTP/3 -+ -+HTTP/3 needs QUIC and QUIC needs TLS. Building libcurl with HTTP/3 and QUIC -+support is not compatible with the MultiSSL feature: they are mutually -+exclusive. If you need MultiSSL in your build, you cannot have HTTP/3 support -+and vice versa. +- rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, +- HTTP2_HUGE_WINDOW_SIZE); ++ // curl-impersonate: ++ // Directly changing the initial window update using users' settings. ++ int current_window_size = nghttp2_session_get_local_window_size(ctx->h2); + -+libcurl can only use a single TLS library with QUIC and that *same* TLS -+library needs to be used for the other TLS using protocols. ++ // Use chrome's value as default ++ int window_update = 15663105; ++ if(data->set.http2_window_update) { ++ window_update = data->set.http2_window_update; ++ } + -+## Configure finding libs in wrong directory - - When the configure script checks for third-party libraries, it adds those - directories to the `LDFLAGS` variable and then tries linking to see if it -@@ -237,7 +253,7 @@ Note: The pre-processor settings can be found using the Visual Studio IDE - under "Project -> Properties -> Configuration Properties -> C/C++ -> - Preprocessor". - --## Using BSD-style lwIP instead of Winsock TCP/IP stack in Win32 builds -+## Using BSD-style lwIP instead of Winsock TCP/IP stack in Windows builds - - In order to compile libcurl and curl using BSD-style lwIP TCP/IP stack it is - necessary to make the definition of the preprocessor symbol `USE_LWIPSOCK` -@@ -505,14 +521,14 @@ disabling support for some feature (run `./configure --help` to see them all): - - `--disable-mime` (MIME API) - - `--disable-netrc` (.netrc file) - - `--disable-ntlm` (NTLM authentication) -- - `--disable-ntlm-wb` (NTLM WinBind) -+ - `--disable-ntlm-wb` (NTLM winbind) - - `--disable-progress-meter` (graphical progress meter in library) - - `--disable-proxy` (HTTP and SOCKS proxies) - - `--disable-pthreads` (multi-threading) - - `--disable-socketpair` (socketpair for asynchronous name resolving) - - `--disable-threaded-resolver` (threaded name resolver) - - `--disable-tls-srp` (Secure Remote Password authentication for TLS) -- - `--disable-unix-sockets` (UNIX sockets) -+ - `--disable-unix-sockets` (Unix sockets) - - `--disable-verbose` (eliminates debugging strings and error code strings) - - `--disable-versioned-symbols` (versioned symbols) - - `--enable-symbol-hiding` (eliminates unneeded symbols in the shared library) -@@ -554,18 +570,18 @@ that are not automatically detected: - - This is a probably incomplete list of known CPU architectures and operating - systems that curl has been compiled for. If you know a system curl compiles --and runs on, that is not listed, please let us know! -+and runs on, that is not listed, please let us know. - - ## 101 Operating Systems - - AIX, AmigaOS, Android, ArcoOS, Aros, Atari FreeMiNT, BeOS, Blackberry 10, - Blackberry Tablet OS, Cell OS, CheriBSD, Chrome OS, Cisco IOS, DG/UX, - Dragonfly BSD, DR DOS, eCOS, FreeBSD, FreeDOS, FreeRTOS, Fuchsia, Garmin OS, -- Genode, Haiku, HardenedBSD, HP-UX, Hurd, Illumos, Integrity, iOS, ipadOS, IRIX, -+ Genode, Haiku, HardenedBSD, HP-UX, Hurd, illumos, Integrity, iOS, ipadOS, IRIX, - Linux, Lua RTOS, Mac OS 9, macOS, Mbed, Meego, Micrium, MINIX, Moblin, MorphOS, - MPE/iX, MS-DOS, NCR MP-RAS, NetBSD, Netware, NextStep, Nintendo Switch, - NonStop OS, NuttX, OpenBSD, OpenStep, Orbis OS, OS/2, OS/400, OS21, Plan 9, -- PlayStation Portable, QNX, Qubes OS, ReactOS, Redox, RICS OS, ROS, RTEMS, -+ PlayStation Portable, QNX, Qubes OS, ReactOS, Redox, RISC OS, ROS, RTEMS, - Sailfish OS, SCO Unix, Serenity, SINIX-Z, SkyOS, Solaris, Sortix, SunOS, - Syllable OS, Symbian, Tizen, TPF, Tru64, tvOS, ucLinux, Ultrix, UNICOS, - UnixWare, VMS, vxWorks, watchOS, Wear OS, WebOS, Wii system software, Wii U, -diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md -index b1a095fe9..ae77f0e54 100644 ---- a/docs/INTERNALS.md -+++ b/docs/INTERNALS.md -@@ -1,3 +1,9 @@ -+ ++ rc = nghttp2_session_set_local_window_size( ++ ctx->h2, NGHTTP2_FLAG_NONE, 0, ++ current_window_size + window_update); + - # curl internals - - The canonical libcurl internals documentation is now in the [everything -@@ -29,7 +35,7 @@ versions of libs and build tools. - - MIT Kerberos 1.2.4 - - Heimdal ? - - nghttp2 1.15.0 -- - WinSock 2.2 (on Windows 95+ and Windows CE .NET 4.1+) -+ - Winsock 2.2 (on Windows 95+ and Windows CE .NET 4.1+) - - ## Build tools - -@@ -41,7 +47,7 @@ versions of libs and build tools. - - GNU Autoconf 2.59 - - GNU Automake 1.7 - - GNU M4 1.4 -- - perl 5.6 -+ - perl 5.8 - - roffit 0.5 - - cmake 3.7 + if(rc) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rc), rc); +@@ -500,6 +657,16 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, + goto out; + } -diff --git a/docs/IPFS.md b/docs/IPFS.md -index 65c0f5dad..82dae9439 100644 ---- a/docs/IPFS.md -+++ b/docs/IPFS.md -@@ -1,3 +1,9 @@ -+ ++#define FIREFOX_DEFAULT_STREAM_ID (15) ++ /* Best effort to set the request's stream id to 15, like Firefox does. */ ++ // Let's ignore this for now, as it seems not to be targeted as fingerprints. ++ // nghttp2_session_set_next_stream_id(ctx->h2, FIREFOX_DEFAULT_STREAM_ID); + - # IPFS - For an overview about IPFS, visit the [IPFS project site](https://ipfs.tech/). - -diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS -index f4ced4d84..5a1e5eeaa 100644 ---- a/docs/KNOWN_BUGS -+++ b/docs/KNOWN_BUGS -@@ -12,13 +12,11 @@ check the changelog of the current development status, as one or more of these - problems may have been fixed or changed somewhat since this was written. - - 1. HTTP -- 1.2 hyper is slow -- 1.5 Expect-100 meets 417 - - 2. TLS -- 2.1 IMAPS connection fails with rustls error -+ 2.1 IMAPS connection fails with Rustls error - 2.3 Unable to use PKCS12 certificate with Secure Transport -- 2.4 Secure Transport will not import PKCS#12 client certificates without a password -+ 2.4 Secure Transport does not import PKCS#12 client certificates without a password - 2.5 Client cert handling with Issuer DN differs between backends - 2.7 Client cert (MTLS) issues with Schannel - 2.11 Schannel TLS 1.2 handshake bug in old Windows versions -@@ -27,33 +25,31 @@ problems may have been fixed or changed somewhat since this was written. - 3. Email protocols - 3.1 IMAP SEARCH ALL truncated response - 3.2 No disconnect command -- 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses - 3.4 AUTH PLAIN for SMTP is not working on all servers - 3.5 APOP authentication fails on POP3 - 3.6 POP3 issue when reading small chunks - - 4. Command line -+ 4.1 -T /dev/stdin may upload with an incorrect content length -+ 4.2 -T - always uploads chunked - - 5. Build and portability issues - 5.1 OS400 port requires deprecated IBM library - 5.2 curl-config --libs contains private details -- 5.3 building for old macOS fails with gcc -- 5.5 cannot handle Unicode arguments in non-Unicode builds on Windows -- 5.6 cygwin: make install installs curl-config.1 twice -- 5.9 Utilize Requires.private directives in libcurl.pc -+ 5.3 LDFLAGS passed too late making libs linked incorrectly -+ 5.6 Cygwin: make install installs curl-config.1 twice - 5.11 configure --with-gssapi with Heimdal is ignored on macOS - 5.12 flaky CI builds - 5.13 long paths are not fully supported on Windows -- 5.14 Windows Unicode builds use homedir in current locale - 5.15 Unicode on Windows - - 6. Authentication -- 6.1 NTLM authentication and unicode - 6.2 MIT Kerberos for Windows build - 6.3 NTLM in system context uses wrong name - 6.5 NTLM does not support password with § character - 6.6 libcurl can fail to try alternatives with --proxy-any - 6.7 Do not clear digest for single realm -+ 6.8 Heimdal memory leaks - 6.9 SHA-256 digest not supported in Windows SSPI builds - 6.10 curl never completes Negotiate over HTTP - 6.11 Negotiate on Windows fails -@@ -61,12 +57,7 @@ problems may have been fixed or changed somewhat since this was written. - 6.13 Negotiate against Hadoop HDFS - - 7. FTP -- 7.1 FTP upload fails if remembered dir is deleted -- 7.2 Implicit FTPS upload timeout -- 7.3 FTP with NOBODY and FAILONERROR - 7.4 FTP with ACCT -- 7.5 FTPS upload, FileZilla, GnuTLS and close_notify -- 7.11 FTPS upload data loss with TLS 1.3 - 7.12 FTPS directory listing hangs on Windows with Schannel - - 9. SFTP and SCP -@@ -74,15 +65,19 @@ problems may have been fixed or changed somewhat since this was written. - 9.2 wolfssh: publickey auth does not work - 9.3 Remote recursive folder creation with SFTP - 9.4 libssh blocking and infinite loop problem -- 9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" -+ 9.5 Cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" - - 10. SOCKS -- 10.3 FTPS over SOCKS - - 11. Internals -+ 11.1 gssapi library name + version is missing in curl_version_info() - 11.2 error buffer not set if connection to multiple addresses fails -+ 11.3 TFTP tests fail on OpenBSD - 11.4 HTTP test server 'connection-monitor' problems - 11.5 Connection information when using TCP Fast Open -+ 11.6 test cases sometimes timeout -+ 11.7 CURLOPT_CONNECT_TO does not work for HTTPS proxy -+ 11.8 WinIDN test failures - - 12. LDAP - 12.1 OpenLDAP hangs after returning results -@@ -99,20 +94,22 @@ problems may have been fixed or changed somewhat since this was written. - 15.3 unusable tool_hugehelp.c with MinGW - 15.6 uses -lpthread instead of Threads::Threads - 15.7 generated .pc file contains strange entries -- 15.11 ExternalProject_Add does not set CURL_CA_PATH - 15.13 CMake build with MIT Kerberos does not work - - 16. aws-sigv4 -- 16.1 aws-sigv4 does not sign requests with * correctly -+ 16.2 aws-sigv4 does not handle multipart/form-data correctly -+ 16.3 aws-sigv4 has problems with particular URLs - 16.6 aws-sigv4 does not behave well with AWS VPC Lattice - - 17. HTTP/2 - 17.1 HTTP/2 prior knowledge over proxy - 17.2 HTTP/2 frames while in the connection pool kill reuse - 17.3 ENHANCE_YOUR_CALM causes infinite retries -+ 17.4 HTTP/2 + TLS spends a lot of time in recv - - 18. HTTP/3 - 18.1 connection migration does not work -+ 18.2 quiche: QUIC connection is draining - - 19. RTSP - 19.1 Some methods do not support response bodies -@@ -121,22 +118,9 @@ problems may have been fixed or changed somewhat since this was written. - - 1. HTTP - --1.2 hyper is slow -- -- When curl is built to use hyper for HTTP, it is unnecessary slow. -- -- https://github.com/curl/curl/issues/11203 -- --1.5 Expect-100 meets 417 -- -- If an upload using Expect: 100-continue receives an HTTP 417 response, it -- ought to be automatically resent without the Expect:. A workaround is for -- the client application to redo the transfer after disabling Expect:. -- https://curl.se/mail/archive-2008-02/0043.html -- - 2. TLS - --2.1 IMAPS connection fails with rustls error -+2.1 IMAPS connection fails with Rustls error - - https://github.com/curl/curl/issues/10457 - -@@ -144,7 +128,7 @@ problems may have been fixed or changed somewhat since this was written. - - See https://github.com/curl/curl/issues/5403 - --2.4 Secure Transport will not import PKCS#12 client certificates without a password -+2.4 Secure Transport does not import PKCS#12 client certificates without a password - - libcurl calls SecPKCS12Import with the PKCS#12 client certificate, but that - function rejects certificates that do not have a password. -@@ -188,12 +172,6 @@ problems may have been fixed or changed somewhat since this was written. - The disconnect commands (LOGOUT and QUIT) may not be sent by IMAP, POP3 and - SMTP if a failure occurs during the authentication phase of a connection. - --3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses -- -- You have to tell libcurl not to expect a body, when dealing with one line -- response commands. Please see the POP3 examples and test cases which show -- this for the NOOP and DELE commands. https://curl.se/bug/?i=740 -- - 3.4 AUTH PLAIN for SMTP is not working on all servers - - Specifying "--login-options AUTH=PLAIN" on the command line does not seem to -@@ -213,6 +191,25 @@ problems may have been fixed or changed somewhat since this was written. - - 4. Command line - -+4.1 -T /dev/stdin may upload with an incorrect content length -+ -+ -T stats the path to figure out its size in bytes to use it as Content-Length -+ if it is a regular file. -+ -+ The problem with that is that, on BSDs and some other UNIXes (not Linux), -+ open(path) may not give you a file descriptor with a 0 offset from the start -+ of the file. -+ -+ See https://github.com/curl/curl/issues/12177 -+ -+4.2 -T - always uploads chunked -+ -+ When the `<` shell operator is used. curl should realise that stdin is a -+ regular file in this case, and that it can do a non-chunked upload, like it -+ would do if you used -T file. -+ -+ See https://github.com/curl/curl/issues/12171 -+ - 5. Build and portability issues - - 5.1 OS400 port requires deprecated IBM library -@@ -225,38 +222,22 @@ problems may have been fixed or changed somewhat since this was written. - - 5.2 curl-config --libs contains private details - -- "curl-config --libs" will include details set in LDFLAGS when configure is -- run that might be needed only for building libcurl. Further, curl-config -- --cflags suffers from the same effects with CFLAGS/CPPFLAGS. -- --5.3 building for old macOS fails with gcc -+ "curl-config --libs" include details set in LDFLAGS when configure is run -+ that might be needed only for building libcurl. Further, curl-config --cflags -+ suffers from the same effects with CFLAGS/CPPFLAGS. - -- Building curl for certain old macOS versions fails when gcc is used. We -- command using clang in those cases. -+5.3 LDFLAGS passed too late making libs linked incorrectly - -- See https://github.com/curl/curl/issues/11441 -- --5.5 cannot handle Unicode arguments in non-Unicode builds on Windows -- -- If a URL or filename cannot be encoded using the user's current codepage then -- it can only be encoded properly in the Unicode character set. Windows uses -- UTF-16 encoding for Unicode and stores it in wide characters, however curl -- and libcurl are not equipped for that at the moment except when built with -- _UNICODE and UNICODE defined. And, except for Cygwin, Windows cannot use UTF-8 -- as a locale. -+ Compiling latest curl on HP-UX and linking against a custom OpenSSL (which is -+ on the default loader/linker path), fails because the generated Makefile has -+ LDFLAGS passed on after LIBS. - -- https://curl.se/bug/?i=345 -- https://curl.se/bug/?i=731 -- https://curl.se/bug/?i=3747 -+ See https://github.com/curl/curl/issues/14893 - --5.6 cygwin: make install installs curl-config.1 twice -+5.6 Cygwin: make install installs curl-config.1 twice - - https://github.com/curl/curl/issues/8839 - --5.9 Utilize Requires.private directives in libcurl.pc -- -- https://github.com/curl/curl/issues/864 -- - 5.11 configure --with-gssapi with Heimdal is ignored on macOS - - ... unless you also pass --with-gssapi-libs -@@ -276,45 +257,58 @@ problems may have been fixed or changed somewhat since this was written. - 5.13 long paths are not fully supported on Windows - - curl on Windows cannot access long paths (paths longer than 260 characters). -- However, as a workaround, the Windows path prefix \\?\ which disables all path -- interpretation may work to allow curl to access the path. For example: -+ However, as a workaround, the Windows path prefix \\?\ which disables all -+ path interpretation may work to allow curl to access the path. For example: - \\?\c:\longpath. - - See https://github.com/curl/curl/issues/8361 - --5.14 Windows Unicode builds use homedir in current locale -- -- The Windows Unicode builds of curl use the current locale, but expect Unicode -- UTF-8 encoded paths for internal use such as open, access and stat. The user's -- home directory is retrieved via curl_getenv in the current locale and not as -- UTF-8 encoded Unicode. -- -- See https://github.com/curl/curl/pull/7252 and -- https://github.com/curl/curl/pull/7281 -- - 5.15 Unicode on Windows - -- Passing in a unicode filename with -o: -+ Passing in a Unicode filename with -o: - - https://github.com/curl/curl/issues/11461 - -- Passing in unicode character with -d: -+ Passing in Unicode character with -d: - - https://github.com/curl/curl/issues/12231 - --6. Authentication -+ Windows Unicode builds use homedir in current locale -+ -+ The Windows Unicode builds of curl use the current locale, but expect Unicode -+ UTF-8 encoded paths for internal use such as open, access and stat. The -+ user's home directory is retrieved via curl_getenv in the current locale and -+ not as UTF-8 encoded Unicode. -+ -+ See https://github.com/curl/curl/pull/7252 and -+ https://github.com/curl/curl/pull/7281 -+ -+ Cannot handle Unicode arguments in non-Unicode builds on Windows -+ -+ If a URL or filename cannot be encoded using the user's current codepage then -+ it can only be encoded properly in the Unicode character set. Windows uses -+ UTF-16 encoding for Unicode and stores it in wide characters, however curl -+ and libcurl are not equipped for that at the moment except when built with -+ _UNICODE and UNICODE defined. Except for Cygwin, Windows cannot use UTF-8 as -+ a locale. -+ -+ https://curl.se/bug/?i=345 -+ https://curl.se/bug/?i=731 -+ https://curl.se/bug/?i=3747 - --6.1 NTLM authentication and unicode -+ NTLM authentication and Unicode - -- NTLM authentication involving unicode user name or password only works -- properly if built with UNICODE defined together with the Schannel -- backend. The original problem was mentioned in: -+ NTLM authentication involving Unicode username or password only works -+ properly if built with UNICODE defined together with the Schannel backend. -+ The original problem was mentioned in: - https://curl.se/mail/lib-2009-10/0024.html - https://curl.se/bug/view.cgi?id=896 - - The Schannel version verified to work as mentioned in - https://curl.se/mail/lib-2012-07/0073.html - -+6. Authentication -+ - 6.2 MIT Kerberos for Windows build - - libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's -@@ -324,8 +318,8 @@ problems may have been fixed or changed somewhat since this was written. - 6.3 NTLM in system context uses wrong name - - NTLM authentication using SSPI (on Windows) when (lib)curl is running in -- "system context" will make it use wrong(?) user name - at least when compared -- to what winhttp does. See https://curl.se/bug/view.cgi?id=535 -+ "system context" makes it use wrong(?) username - at least when compared to -+ what winhttp does. See https://curl.se/bug/view.cgi?id=535 - - 6.5 NTLM does not support password with § character - -@@ -334,11 +328,11 @@ problems may have been fixed or changed somewhat since this was written. - 6.6 libcurl can fail to try alternatives with --proxy-any - - When connecting via a proxy using --proxy-any, a failure to establish an -- authentication will cause libcurl to abort trying other options if the -- failed method has a higher preference than the alternatives. As an example, -+ authentication causes libcurl to abort trying other options if the failed -+ method has a higher preference than the alternatives. As an example, - --proxy-any against a proxy which advertise Negotiate and NTLM, but which -- fails to set up Kerberos authentication will not proceed to try authentication -- using NTLM. -+ fails to set up Kerberos authentication does not proceed to try -+ authentication using NTLM. - - https://github.com/curl/curl/issues/876 - -@@ -346,6 +340,13 @@ problems may have been fixed or changed somewhat since this was written. - - https://github.com/curl/curl/issues/3267 - -+6.8 Heimdal memory leaks -+ -+ Running test 2077 and 2078 with curl built to do GSS with Heimdal causes -+ valgrind errors (memory leak). -+ -+ https://github.com/curl/curl/issues/14446 -+ - 6.9 SHA-256 digest not supported in Windows SSPI builds - - Windows builds of curl that have SSPI enabled use the native Windows API calls -@@ -381,62 +382,19 @@ problems may have been fixed or changed somewhat since this was written. - - 7. FTP - --7.1 FTP upload fails if remembered dir is deleted -- -- curl's FTP code assumes that the directory it entered in a previous transfer -- still exists when it comes back to do a second transfer, and does not respond -- well if it was indeed deleted in the mean time. -- -- https://github.com/curl/curl/issues/12181 -- --7.2 Implicit FTPS upload timeout -- -- https://github.com/curl/curl/issues/11720 -- --7.3 FTP with NOBODY and FAILONERROR -- -- It seems sensible to be able to use CURLOPT_NOBODY and CURLOPT_FAILONERROR -- with FTP to detect if a file exists or not, but it is not working: -- https://curl.se/mail/lib-2008-07/0295.html -- - 7.4 FTP with ACCT - - When doing an operation over FTP that requires the ACCT command (but not when -- logging in), the operation will fail since libcurl does not detect this and -- thus fails to issue the correct command: -- https://curl.se/bug/view.cgi?id=635 -- --7.5 FTPS upload, FileZilla, GnuTLS and close_notify -- -- An issue where curl does not send the TLS alert close_notify, which triggers -- the wrath of GnuTLS in FileZilla server, and a FTP reply 426 ECONNABORTED. -- -- https://github.com/curl/curl/issues/11383 -- --7.11 FTPS upload data loss with TLS 1.3 -- -- During FTPS upload curl does not attempt to read TLS handshake messages sent -- after the initial handshake. OpenSSL servers running TLS 1.3 may send such a -- message. When curl closes the upload connection if unread data has been -- received (such as a TLS handshake message) then the TCP protocol sends an -- RST to the server, which may cause the server to discard or truncate the -- upload if it has not read all sent data yet, and then return an error to curl -- on the control channel connection. -- -- Since 7.78.0 this is mostly fixed. curl will do a single read before closing -- TLS connections (which causes the TLS library to read handshake messages), -- however there is still possibility of an RST if more messages need to be read -- or a message arrives after the read but before close (network race condition). -- -- https://github.com/curl/curl/issues/6149 -+ logging in), the operation fails since libcurl does not detect this and thus -+ fails to issue the correct command: https://curl.se/bug/view.cgi?id=635 - - 7.12 FTPS server compatibility on Windows with Schannel - -- FTPS is not widely used with the Schannel TLS backend and so there may be more -- bugs compared to other TLS backends such as OpenSSL. In the past users have -- reported hanging and failed connections. It's very likely some changes to curl -- since then fixed the issues. None of the reported issues can be reproduced any -- longer. -+ FTPS is not widely used with the Schannel TLS backend and so there may be -+ more bugs compared to other TLS backends such as OpenSSL. In the past users -+ have reported hanging and failed connections. It is likely some changes to -+ curl since then fixed the issues. None of the reported issues can be -+ reproduced any longer. - - If you encounter an issue connecting to your server via FTPS with the latest - curl and Schannel then please search for open issues or file a new issue. -@@ -471,32 +429,40 @@ problems may have been fixed or changed somewhat since this was written. - - In the SSH_SFTP_INIT state for libssh, the ssh session working mode is set to - blocking mode. If the network is suddenly disconnected during sftp -- transmission, curl will be stuck, even if curl is configured with a timeout. -+ transmission, curl is stuck, even if curl is configured with a timeout. - - https://github.com/curl/curl/issues/8632 - --9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" -+9.5 Cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!" - -- Running SCP and SFTP tests on cygwin makes this warning message appear. -+ Running SCP and SFTP tests on Cygwin makes this warning message appear. - - https://github.com/curl/curl/issues/11244 - - 10. SOCKS - --10.3 FTPS over SOCKS -+11. Internals - -- libcurl does not support FTPS over a SOCKS proxy. -+11.1 gssapi library name + version is missing in curl_version_info() - -+ The struct needs to be expanded and code added to store this info. - --11. Internals -+ See https://github.com/curl/curl/issues/13492 - - 11.2 error buffer not set if connection to multiple addresses fails - - If you ask libcurl to resolve a hostname like example.com to IPv6 addresses -- only. But you only have IPv4 connectivity. libcurl will correctly fail with -- CURLE_COULDNT_CONNECT. But the error buffer set by CURLOPT_ERRORBUFFER -+ when you only have IPv4 connectivity. libcurl fails with -+ CURLE_COULDNT_CONNECT, but the error buffer set by CURLOPT_ERRORBUFFER - remains empty. Issue: https://github.com/curl/curl/issues/544 - -+11.3 TFTP tests fail on OpenBSD -+ -+ When adding an OpenBSD job with tests to GHA, some tests consistently fail -+ to run. -+ -+ See https://github.com/curl/curl/issues/13623 -+ - 11.4 HTTP test server 'connection-monitor' problems - - The 'connection-monitor' feature of the sws HTTP test server does not work -@@ -512,6 +478,23 @@ problems may have been fixed or changed somewhat since this was written. - See https://github.com/curl/curl/issues/1332 and - https://github.com/curl/curl/issues/4296 - -+11.6 test cases sometimes timeout -+ -+ Occasionally, one of the tests timeouts. Inexplicably. -+ -+ See https://github.com/curl/curl/issues/13350 -+ -+11.7 CURLOPT_CONNECT_TO does not work for HTTPS proxy -+ -+ It is unclear if the same option should even cover the proxy connection or if -+ if requires a separate option. -+ -+ See https://github.com/curl/curl/issues/14481 -+ -+11.8 WinIDN test failures -+ -+ Test 165 disabled when built with WinIDN. -+ - 12. LDAP - - 12.1 OpenLDAP hangs after returning results -@@ -553,8 +536,8 @@ problems may have been fixed or changed somewhat since this was written. - 13.2 Trying local ports fails on Windows - - This makes '--local-port [range]' to not work since curl cannot properly -- detect if a port is already in use, so it will try the first port, use that and -- then subsequently fail anyway if that was actually in use. -+ detect if a port is already in use, so it tries the first port, uses that and -+ then subsequently fails anyway if that was actually in use. - - https://github.com/curl/curl/issues/8112 - -@@ -566,12 +549,6 @@ problems may have been fixed or changed somewhat since this was written. - - https://github.com/curl/curl/issues/11158 - --15.2 support build with GnuTLS -- --15.3 unusable tool_hugehelp.c with MinGW -- -- see https://github.com/curl/curl/issues/3125 -- - 15.6 uses -lpthread instead of Threads::Threads - - See https://github.com/curl/curl/issues/6166 -@@ -583,13 +560,6 @@ problems may have been fixed or changed somewhat since this was written. - - See https://github.com/curl/curl/issues/6167 - --15.11 ExternalProject_Add does not set CURL_CA_PATH -- -- CURL_CA_BUNDLE and CURL_CA_PATH are not set properly when cmake's -- ExternalProject_Add is used to build curl as a dependency. -- -- See https://github.com/curl/curl/issues/6313 -- - 15.13 CMake build with MIT Kerberos does not work - - Minimum CMake version was bumped in curl 7.71.0 (#5358) Since CMake 3.2 -@@ -603,9 +573,13 @@ problems may have been fixed or changed somewhat since this was written. - - 16. aws-sigv4 - --16.1 aws-sigv4 does not sign requests with * correctly -+16.2 aws-sigv4 does not handle multipart/form-data correctly + /* all set, traffic will be send on connect */ + result = CURLE_OK; + CURL_TRC_CF(data, cf, "[0] created h2 session%s", +@@ -1716,11 +1883,19 @@ out: + return rv; + } -- https://github.com/curl/curl/issues/7559 -+ https://github.com/curl/curl/issues/13351 -+ -+16.3 aws-sigv4 has problems with particular URLs ++/* ++ * curl-impersonate: Use Chrome's default HTTP/2 stream weight ++ * instead of NGINX default stream weight. ++ */ ++#define CHROME_DEFAULT_STREAM_WEIGHT (256) ++#define SAFARI_DEFAULT_STREAM_WEIGHT (255) ++#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) + -+ https://github.com/curl/curl/issues/13058 - - 16.6 aws-sigv4 does not behave well with AWS VPC Lattice - -@@ -620,9 +594,9 @@ problems may have been fixed or changed somewhat since this was written. - 17.2 HTTP/2 frames while in the connection pool kill reuse - - If the server sends HTTP/2 frames (like for example an HTTP/2 PING frame) to -- curl while the connection is held in curl's connection pool, the socket will -- be found readable when considered for reuse and that makes curl think it is -- dead and then it will be closed and a new connection gets created instead. -+ curl while the connection is held in curl's connection pool, the socket is -+ found readable when considered for reuse and that makes curl think it is dead -+ and then it is closed and a new connection gets created instead. - - This is *best* fixed by adding monitoring to connections while they are kept - in the pool so that pings can be responded to appropriately. -@@ -634,18 +608,34 @@ problems may have been fixed or changed somewhat since this was written. + static int sweight_wanted(const struct Curl_easy *data) + { + /* 0 weight is not set by user and we take the nghttp2 default one */ + return data->set.priority.weight? +- data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; ++ data->set.priority.weight : CHROME_DEFAULT_STREAM_WEIGHT; + } - See https://github.com/curl/curl/issues/5119 + static int sweight_in_effect(const struct Curl_easy *data) +@@ -1736,12 +1911,23 @@ static int sweight_in_effect(const struct Curl_easy *data) + * struct. + */ -+17.4 HTTP/2 + TLS spends a lot of time in recv -+ -+ It has been observered that by making the speed limit less accurate we could -+ improve this performance. (by reverting -+ https://github.com/curl/curl/commit/db5c9f4f9e0779b49624752b135281a0717b277b) -+ Can we find a golden middle ground? ++/* ++ * curl-impersonate: By default Firefox uses stream 13 as the "parent" of the ++ * stream that fetches the main html resource of the web page. ++ */ ++#define FIREFOX_DEFAULT_STREAM_DEP (13) + -+ See https://curl.se/mail/lib-2024-05/0026.html and -+ https://github.com/curl/curl/issues/13416 + static void h2_pri_spec(struct Curl_easy *data, + nghttp2_priority_spec *pri_spec) + { + struct Curl_data_priority *prio = &data->set.priority; + struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent); + int32_t depstream_id = depstream? depstream->id:0; ++ // int32_t depstream_id = depstream? depstream->id:FIREFOX_DEFAULT_STREAM_DEP; + - 18. HTTP/3 - - 18.1 connection migration does not work ++ /* curl-impersonate: Set stream exclusive flag based on user option. ++ * Use data->set, not data->state. ++ */ + nghttp2_priority_spec_init(pri_spec, depstream_id, + sweight_wanted(data), + data->set.priority.exclusive); +@@ -1761,20 +1947,24 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, + struct h2_stream_ctx *stream = H2_STREAM_CTX(data); + int rv = 0; - https://github.com/curl/curl/issues/7695 ++ /* curl-impersonate: Check if stream exclusive flag is true. */ + if(stream && stream->id > 0 && + ((sweight_wanted(data) != sweight_in_effect(data)) || +- (data->set.priority.exclusive != data->state.priority.exclusive) || +- (data->set.priority.parent != data->state.priority.parent)) ) { ++ (data->set.priority.exclusive != 1) || ++ (data->set.priority.parent != data->state.priority.parent))) { + /* send new weight and/or dependency */ + nghttp2_priority_spec pri_spec; -+18.2 quiche: QUIC connection is draining -+ -+ The transfer ends with error "QUIC connection is draining". -+ -+ https://github.com/curl/curl/issues/12037 -+ - 19. RTSP + h2_pri_spec(data, &pri_spec); +- CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); +- DEBUGASSERT(stream->id != -1); +- rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, +- stream->id, &pri_spec); +- if(rv) +- goto out; ++ /* curl-impersonate: Don't send PRIORITY frames for main stream. */ ++ if(stream->id != 1) { ++ CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); ++ DEBUGASSERT(stream->id != -1); ++ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, ++ stream->id, &pri_spec); ++ if(rv) ++ goto out; ++ } + } - 19.1 Some methods do not support response bodies + ctx->nw_out_blocked = 0; +diff --git a/lib/http2.h b/lib/http2.h +index 80e183480..8ee390b7e 100644 +--- a/lib/http2.h ++++ b/lib/http2.h +@@ -31,7 +31,8 @@ - The RTSP implementation is written to assume that a number of RTSP methods -- will always get responses without bodies, even though there seems to be no -+ always get responses without bodies, even though there seems to be no - indication in the RFC that this is always the case. + /* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting + from the peer */ +-#define DEFAULT_MAX_CONCURRENT_STREAMS 100 ++/* curl-impersonate: Use 1000 concurrent streams like Chrome. */ ++#define DEFAULT_MAX_CONCURRENT_STREAMS 1000 - https://github.com/curl/curl/issues/12414 -diff --git a/docs/MAIL-ETIQUETTE.md b/docs/MAIL-ETIQUETTE.md + /* + * Store nghttp2 version info in this buffer. +diff --git a/lib/impersonate.c b/lib/impersonate.c new file mode 100644 -index 000000000..3de77b17b +index 000000000..525e61ff1 --- /dev/null -+++ b/docs/MAIL-ETIQUETTE.md -@@ -0,0 +1,258 @@ -+ -+ -+# Mail etiquette -+ -+## About the lists -+ -+### Mailing Lists -+ -+The mailing lists we have are all listed and described on the [curl -+website](https://curl.se/mail/). -+ -+Each mailing list is targeted to a specific set of users and subjects, please -+use the one or the ones that suit you the most. -+ -+Each mailing list has hundreds up to thousands of readers, meaning that each -+mail sent is received and read by a large number of people. People from -+various cultures, regions, religions and continents. -+ -+### Netiquette -+ -+Netiquette is a common term for how to behave on the Internet. Of course, in -+each particular group and subculture there are differences in what is -+acceptable and what is considered good manners. -+ -+This document outlines what we in the curl project consider to be good -+etiquette, and primarily this focus on how to behave on and how to use our -+mailing lists. -+ -+### Do Not Mail a Single Individual -+ -+Many people send one question to one person. One person gets many mails, and -+there is only one person who can give you a reply. The question may be -+something that other people would also like to ask. These other people have no -+way to read the reply, but to ask the one person the question. The one person -+consequently gets overloaded with mail. -+ -+If you really want to contact an individual and perhaps pay for his or her -+services, by all means go ahead, but if it is just another curl question, take -+it to a suitable list instead. -+ -+### Subscription Required -+ -+All curl mailing lists require that you are subscribed to allow a mail to go -+through to all the subscribers. -+ -+If you post without being subscribed (or from a different mail address than -+the one you are subscribed with), your mail is simply silently discarded. You -+have to subscribe first, then post. -+ -+The reason for this unfortunate and strict subscription policy is of course to -+stop spam from pestering the lists. -+ -+### Moderation of new posters -+ -+Several of the curl mailing lists automatically make all posts from new -+subscribers be moderated. After you have subscribed and sent your first mail -+to a list, that mail is not let through to the list until a mailing list -+administrator has verified that it is OK and permits it to get posted. -+ -+Once a first post has been made that proves the sender is actually talking -+about curl-related subjects, the moderation "flag" is switched off and future -+posts go through without being moderated. -+ -+The reason for this moderation policy is that we do suffer from spammers who -+actually subscribe and send spam to our lists. -+ -+### Handling trolls and spam -+ -+Despite our good intentions and hard work to keep spam off the lists and to -+maintain a friendly and positive atmosphere, there are times when spam and or -+trolls get through. -+ -+Troll - "someone who posts inflammatory, extraneous, or off-topic messages in -+an online community" -+ -+Spam - "use of electronic messaging systems to send unsolicited bulk messages" -+ -+No matter what, we NEVER EVER respond to trolls or spammers on the list. If -+you believe the list admin should do something in particular, contact them -+off-list. The subject is taken care of as much as possible to prevent repeated -+offenses, but responding on the list to such messages never leads to anything -+good and only puts the light even more on the offender: which was the entire -+purpose of it getting sent to the list in the first place. -+ -+Do not feed the trolls. -+ -+### How to unsubscribe -+ -+You can unsubscribe the same way you subscribed in the first place. You go to -+the page for the particular mailing list you are subscribed to and you enter -+your email address and password and press the unsubscribe button. -+ -+Also, the instructions to unsubscribe are included in the headers of every -+mail that is sent out to all curl related mailing lists and there is a footer -+in each mail that links to the "admin" page on which you can unsubscribe and -+change other options. -+ -+You NEVER EVER email the mailing list requesting someone else to take you off -+the list. -+ -+### I posted, now what? -+ -+If you are not subscribed with the same email address that you used to send -+the email, your post is silently discarded. -+ -+If you posted for the first time to the mailing list, you first need to wait -+for an administrator to allow your email to go through (moderated). This -+normally happens quickly but in case we are asleep, you may have to wait a few -+hours. -+ -+Once your email goes through it is sent out to several hundred or even -+thousands of recipients. Your email may cover an area that not that many -+people know about or are interested in. Or possibly the person who knows about -+it is on vacation or under a heavy work load right now. You may have to wait -+for a response and you should not expect to get a response at all. Ideally, -+you get an answer within a couple of days. -+ -+You do yourself and all of us a service when you include as many details as -+possible already in your first email. Mention your operating system and -+environment. Tell us which curl version you are using and tell us what you -+did, what happened and what you expected would happen. Preferably, show us -+what you did with details enough to allow others to help point out the problem -+or repeat the steps in their locations. -+ -+Failing to include details only delays responses and make people respond and -+ask for more details and you have to send follow-up emails that include them. -+ -+Expect the responses to primarily help YOU debug the issue, or ask YOU -+questions that can lead you or others towards a solution or explanation to -+whatever you experience. -+ -+If you are a repeat offender to the guidelines outlined in this document, -+chances are that people ignore you and your chances to get responses in the -+future greatly diminish. -+ -+### Your emails are public ++++ b/lib/impersonate.c +@@ -0,0 +1,1177 @@ ++#include "curl_setup.h" + -+Your email, its contents and all its headers and the details in those headers -+are received by every subscriber of the mailing list that you send your email -+to. ++#include + -+Your email as sent to a curl mailing list ends up in mail archives, on the -+curl website and elsewhere, for others to see and read. Today and in the -+future. In addition to the archives, the mail is sent out to thousands of -+individuals. There is no way to undo a sent email. ++#include "impersonate.h" + -+When sending emails to a curl mailing list, do not include sensitive -+information such as usernames and passwords; use fake ones, temporary ones or -+just remove them completely from the mail. Note that this includes base64 -+encoded HTTP Basic auth headers. -+ -+This public nature of the curl mailing lists makes automatically inserted mail -+footers about mails being "private" or "only meant for the recipient" or -+similar even more silly than usual. Because they are absolutely not private -+when sent to a public mailing list. -+ -+## Sending mail -+ -+### Reply or New Mail -+ -+Please do not reply to an existing message as a short-cut to post a message to -+the lists. -+ -+Many mail programs and web archivers use information within mails to keep them -+together as "threads", as collections of posts that discuss a certain subject. -+If you do not intend to reply on the same or similar subject, do not just hit -+reply on an existing mail and change the subject, create a new mail. -+ -+### Reply to the List -+ -+When replying to a message from the list, make sure that you do "group reply" -+or "reply to all", and not just reply to the author of the single mail you -+reply to. -+ -+We are actively discouraging replying to the single person by setting the -+correct field in outgoing mails back asking for replies to get sent to the -+mailing list address, making it harder for people to reply to the author only -+by mistake. -+ -+### Use a Sensible Subject -+ -+Please use a subject of the mail that makes sense and that is related to the -+contents of your mail. It makes it a lot easier to find your mail afterwards -+and it makes it easier to track mail threads and topics. -+ -+### Do Not Top-Post -+ -+If you reply to a message, do not use top-posting. Top-posting is when you -+write the new text at the top of a mail and you insert the previous quoted -+mail conversation below. It forces users to read the mail in a backwards order -+to properly understand it. -+ -+This is why top posting is so bad (in top posting order): -+ -+ A: Because it messes up the order in which people normally read text. -+ Q: Why is top-posting such a bad thing? -+ A: Top-posting. -+ Q: What is the most annoying thing in email? -+ -+Apart from the screwed up read order (especially when mixed together in a -+thread when someone responds using the mandated bottom-posting style), it also -+makes it impossible to quote only parts of the original mail. -+ -+When you reply to a mail. You let the mail client insert the previous mail -+quoted. Then you put the cursor on the first line of the mail and you move -+down through the mail, deleting all parts of the quotes that do not add -+context for your comments. When you want to add a comment you do so, inline, -+right after the quotes that relate to your comment. Then you continue -+downwards again. -+ -+When most of the quotes have been removed and you have added your own words, -+you are done. -+ -+### HTML is not for mails -+ -+Please switch off those HTML encoded messages. You can mail all those funny -+mails to your friends. We speak plain text mails. -+ -+### Quoting -+ -+Quote as little as possible. Just enough to provide the context you cannot -+eave out. A lengthy description can be found -+[here](https://www.netmeister.org/news/learn2quote.html). -+ -+### Digest -+ -+We allow subscribers to subscribe to the "digest" version of the mailing -+lists. A digest is a collection of mails lumped together in one single mail. -+ -+Should you decide to reply to a mail sent out as a digest, there are two -+things you MUST consider if you really, really cannot subscribe normally -+instead: -+ -+Cut off all mails and chatter that is not related to the mail you want to -+reply to. -+ -+Change the subject name to something sensible and related to the subject, -+preferably even the actual subject of the single mail you wanted to reply to -+ -+### Please Tell Us How You Solved The Problem -+ -+Many people mail questions to the list, people spend some of their time and -+make an effort in providing good answers to these questions. -+ -+If you are the one who asks, please consider responding once more in case one -+of the hints was what solved your problems. The guys who write answers feel -+good to know that they provided a good answer and that you fixed the problem. -+Far too often, the person who asked the question is never heard from again, -+and we never get to know if they are gone because the problem was solved or -+perhaps because the problem was unsolvable. -+ -+Getting the solution posted also helps other users that experience the same -+problem(s). They get to see (possibly in the web archives) that the suggested -+fixes actually have helped at least one person. -diff --git a/docs/MANUAL.md b/docs/MANUAL.md -index 3ce869413..35a944849 100644 ---- a/docs/MANUAL.md -+++ b/docs/MANUAL.md -@@ -1,3 +1,9 @@ -+ -+ - # curl tutorial - - ## Simple Usage -@@ -268,7 +274,7 @@ To get even more details and information on what curl does, try using the - `--trace` or `--trace-ascii` options with a given filename to log to, like - this: - -- curl --trace trace.txt www.haxx.se -+ curl --trace my-trace.txt www.haxx.se - - - ## Detailed Information -@@ -303,7 +309,8 @@ Post a simple `name` and `phone` guestbook. - - Or automatically [URL encode the data](https://everything.curl.dev/http/post/url-encode). - -- curl --data-urlencode "name=Rafael Sagula&phone=3320780" http://www.example.com/guest.cgi -+ curl --data-urlencode "name=Rafael Sagula&phone=3320780" -+ http://www.example.com/guest.cgi - - How to post a form with curl, lesson #1: - -@@ -337,7 +344,8 @@ We want to enter user `foobar` with password `12345`. - - To post to this, you would enter a curl command line like: - -- curl -d "user=foobar&pass=12345&id=blablabla&ding=submit" http://example.com/post.cgi -+ curl -d "user=foobar&pass=12345&id=blablabla&ding=submit" -+ http://example.com/post.cgi - - While `-d` uses the application/x-www-form-urlencoded mime-type, generally - understood by CGI's and similar, curl also supports the more capable -diff --git a/docs/Makefile.am b/docs/Makefile.am -index ca7b08334..e8f2d55bf 100644 ---- a/docs/Makefile.am -+++ b/docs/Makefile.am -@@ -28,9 +28,9 @@ if BUILD_DOCS - # if we disable man page building, ignore these - MK_CA_DOCS = mk-ca-bundle.1 - CURLCONF_DOCS = curl-config.1 -+man_MANS = curl-config.1 - endif - --man_MANS = curl-config.1 - CURLPAGES = curl-config.md mk-ca-bundle.md - - SUBDIRS = . cmdline-opts libcurl -@@ -40,51 +40,59 @@ if BUILD_DOCS - CLEANFILES = mk-ca-bundle.1 curl-config.1 - endif - -+INTERNALDOCS = \ -+ internals/BUFQ.md \ -+ internals/BUFREF.md \ -+ internals/CHECKSRC.md \ -+ internals/CLIENT-READERS.md \ -+ internals/CLIENT-WRITERS.md \ -+ internals/CODE_STYLE.md \ -+ internals/CONNECTION-FILTERS.md \ -+ internals/DYNBUF.md \ -+ internals/HASH.md \ -+ internals/HYPER.md \ -+ internals/LLIST.md \ -+ internals/MQTT.md \ -+ internals/NEW-PROTOCOL.md \ -+ internals/README.md \ -+ internals/SPLAY.md \ -+ internals/WEBSOCKET.md -+ - EXTRA_DIST = \ - $(CURLPAGES) \ -- $(CURLCONF_DOCS) \ -- ALTSVC.md \ -+ $(INTERNALDOCS) \ - BINDINGS.md \ -- BUFREF.md \ - BUG-BOUNTY.md \ - BUGS.md \ -- CHECKSRC.md \ - CIPHERS.md \ -+ CIPHERS-TLS12.md \ - CMakeLists.txt \ - CODE_OF_CONDUCT.md \ - CODE_REVIEW.md \ -- CODE_STYLE.md \ -- CLIENT-READERS.md \ -- CLIENT-WRITERS.md \ -- CONNECTION-FILTERS.md \ - CONTRIBUTE.md \ - CURL-DISABLE.md \ - CURLDOWN.md \ - DEPRECATE.md \ - DISTROS.md \ -- DYNBUF.md \ - EARLY-RELEASE.md \ -+ ECH.md \ - EXPERIMENTAL.md \ - FAQ \ - FEATURES.md \ - GOVERNANCE.md \ - HELP-US.md \ - HISTORY.md \ -- HSTS.md \ - HTTP-COOKIES.md \ -- HTTP2.md \ - HTTP3.md \ -- HYPER.md \ - INSTALL \ - INSTALL-CMAKE.md \ - INSTALL.md \ - INTERNALS.md \ -+ IPFS.md \ - KNOWN_BUGS \ -- MAIL-ETIQUETTE \ -- MQTT.md \ -- NEW-PROTOCOL.md \ -+ MAIL-ETIQUETTE.md \ -+ MANUAL.md \ - options-in-versions \ -- PARALLEL-TRANSFERS.md \ - README.md \ - RELEASE-PROCEDURE.md \ - RUSTLS.md \ -@@ -93,13 +101,11 @@ EXTRA_DIST = \ - SPONSORS.md \ - SSL-PROBLEMS.md \ - SSLCERTS.md \ -- THANKS \ -- TODO \ -+ THANKS TODO \ - TheArtOfHttpScripting.md \ - URL-SYNTAX.md \ - VERSIONS.md \ -- VULN-DISCLOSURE-POLICY.md \ -- WEBSOCKET.md -+ VULN-DISCLOSURE-POLICY.md - - CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ - -@@ -110,7 +116,7 @@ CD2_ = $(CD2_0) - - SUFFIXES = .1 .md - --all: $(MK_CA_DOCS) -+all: $(MK_CA_DOCS) $(CURLCONF_DOCS) - - .md.1: - $(CD2)$(CD2NROFF) -diff --git a/docs/README.md b/docs/README.md -index 59f4bd147..22d96ea9b 100644 ---- a/docs/README.md -+++ b/docs/README.md -@@ -1,3 +1,9 @@ -+ -+ - ![curl logo](https://curl.se/logo/curl-logo.svg) - - # Documentation -diff --git a/docs/RELEASE-PROCEDURE.md b/docs/RELEASE-PROCEDURE.md -index e48a4d28a..043e3afd0 100644 ---- a/docs/RELEASE-PROCEDURE.md -+++ b/docs/RELEASE-PROCEDURE.md -@@ -1,11 +1,15 @@ -+ -+ - curl release procedure - how to do a release - ============================================ - - in the source code repo - ----------------------- - --- run `./scripts/copyright.pl` and correct possible omissions -- - - edit `RELEASE-NOTES` to be accurate - - - update `docs/THANKS` -@@ -16,9 +20,7 @@ in the source code repo - tag and we use underscores instead of dots in the version number. Make sure - the tag is GPG signed (using -s). - --- run `./maketgz 7.34.0` to build the release tarballs. It is important that -- you run this on a machine with the correct set of autotools etc installed as -- this is what is shipped and used by most users on \*nix like systems. -+- run `./scripts/dmaketgz 7.34.0` to build the release tarballs. - - - push the git commits and the new tag - -@@ -106,11 +108,11 @@ Coming dates - Based on the description above, here are some planned release dates (at the - time of this writing): - --- May 22, 2024 --- July 17, 2024 - - September 11, 2024 - - November 6, 2024 - - January 8, 2025 - - March 5, 2025 - - April 30, 2025 - - June 25, 2025 -+- August 20, 2025 -+- October 15, 2025 -diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md -index 464293834..abf306b33 100644 ---- a/docs/ROADMAP.md -+++ b/docs/ROADMAP.md -@@ -1,24 +1,17 @@ -+ -+ - # curl the next few years - perhaps - - Roadmap of things Daniel Stenberg wants to work on next. It is intended to - serve as a guideline for others for information, feedback and possible - participation. - --## "Complete" the HTTP/3 support -- --curl has experimental support for HTTP/3 since a good while back. There are --some functionality missing and once the final specs are published we want to --eventually remove the "experimental" label from this functionality. -- --## HTTPS DNS records -- --As a DNS version of alt-svc and also a pre-requisite for ECH (see below). -- --See: https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-02 -- --## ECH (Encrypted Client Hello - formerly known as ESNI) -+## WebSocket - -- See Daniel's post on [Support of Encrypted -- SNI](https://curl.se/mail/lib-2019-03/0000.html) on the mailing list. -+Agree that it is a good enough API and remove the EXPERIMENTAL label. - -- Initial work exists in [PR 4011](https://github.com/curl/curl/pull/4011) -+## -diff --git a/docs/RUSTLS.md b/docs/RUSTLS.md -index 3515e1666..47af01a53 100644 ---- a/docs/RUSTLS.md -+++ b/docs/RUSTLS.md -@@ -1,26 +1,36 @@ -+ -+ - # Rustls - - [Rustls is a TLS backend written in Rust](https://docs.rs/rustls/). Curl can - be built to use it as an alternative to OpenSSL or other TLS backends. We use - the [rustls-ffi C bindings](https://github.com/rustls/rustls-ffi/). This --version of curl depends on version v0.12.0 of rustls-ffi. -+version of curl depends on version v0.14.0 of rustls-ffi. - --# Building with rustls -+# Building with Rustls - - First, [install Rust](https://rustup.rs/). - - Next, check out, build, and install the appropriate version of rustls-ffi: - -- % cargo install cbindgen -- % git clone https://github.com/rustls/rustls-ffi -b v0.12.0 -+ % git clone https://github.com/rustls/rustls-ffi -b v0.14.0 - % cd rustls-ffi - % make - % make DESTDIR=${HOME}/rustls-ffi-built/ install - --Now configure and build curl with rustls: -+Now configure and build curl with Rustls: - - % git clone https://github.com/curl/curl - % cd curl - % autoreconf -fi - % ./configure --with-rustls=${HOME}/rustls-ffi-built - % make -+ -+See the [rustls-ffi README] for more information on cryptography providers and -+their build/platform requirements. -+ -+[rustls-ffi README]: https://github.com/rustls/rustls-ffi/blob/main/README.md#cryptography-provide -diff --git a/docs/SECURITY-ADVISORY.md b/docs/SECURITY-ADVISORY.md -index 8d908a8ca..efb0e0493 100644 ---- a/docs/SECURITY-ADVISORY.md -+++ b/docs/SECURITY-ADVISORY.md -@@ -1,3 +1,9 @@ -+ -+ - # Anatomy of a curl security advisory - - As described in the [Security Process](https://curl.se/dev/secprocess.html) -diff --git a/docs/SPONSORS.md b/docs/SPONSORS.md -index bec96809c..c9cf42a7f 100644 ---- a/docs/SPONSORS.md -+++ b/docs/SPONSORS.md -@@ -1,3 +1,9 @@ -+ -+ - # curl sponsors - - A sponsor is someone who donates money or resources to the curl project for no -@@ -38,4 +44,4 @@ gambling, pornography, social media manipulation etc. - ## Past Sponsors - - Sponsors that stop paying are considered *Past Sponsors* and are not displayed --on the sponsor page anymore. We thank you for your contributions! -+on the sponsor page anymore. We thank you for your contributions. -diff --git a/docs/SSL-PROBLEMS.md b/docs/SSL-PROBLEMS.md -index 86262222f..620392c4e 100644 ---- a/docs/SSL-PROBLEMS.md -+++ b/docs/SSL-PROBLEMS.md -@@ -1,8 +1,8 @@ -- _ _ ____ _ -- ___| | | | _ \| | -- / __| | | | |_) | | -- | (__| |_| | _ <| |___ -- \___|\___/|_| \_\_____| -+ - - # SSL problems - -@@ -44,7 +44,7 @@ - when connecting to make the connection succeed. - - An additional complication can be that modern SSL libraries sometimes are -- built with support for older SSL and TLS versions disabled! -+ built with support for older SSL and TLS versions disabled. - - All versions of SSL and the TLS versions before 1.2 are considered insecure - and should be avoided. Use TLS 1.2 or later. -diff --git a/docs/SSLCERTS.md b/docs/SSLCERTS.md -index caac51c42..300039c73 100644 ---- a/docs/SSLCERTS.md -+++ b/docs/SSLCERTS.md -@@ -1,154 +1,123 @@ --SSL Certificate Verification --============================ -+ - --SSL is the old name. It is called TLS these days. -+# TLS Certificate Verification - --Native SSL ------------ -+## Native vs file based - --If libcurl was built with Schannel or Secure Transport support (the native SSL --libraries included in Windows and Mac OS X), then this does not apply to --you. Scroll down for details on how the OS-native engines handle SSL --certificates. If you are not sure, then run "curl -V" and read the results. If --the version string says `Schannel` in it, then it was built with Schannel --support. -+If curl was built with Schannel or Secure Transport support, then curl uses -+the system native CA store for verification. All other TLS libraries use a -+file based CA store by default. - --It is about trust ------------------- -+## Verification - --This system is about trust. In your local CA certificate store you have certs --from *trusted* Certificate Authorities that you then can use to verify that --the server certificates you see are valid. They are signed by one of the --certificate authorities you trust. -+Every trusted server certificate is digitally signed by a Certificate -+Authority, a CA. - --Which certificate authorities do you trust? You can decide to trust the same --set of companies your operating system trusts, or the set one of the known --browsers trust. That is basically trust via someone else you trust. You should --just be aware that modern operating systems and browsers are setup to trust --*hundreds* of companies and in recent years several certificate authorities --have been found untrustworthy. -+In your local CA store you have a collection of certificates from *trusted* -+certificate authorities that TLS clients like curl use to verify servers. - --Certificate Verification -------------------------- -- --libcurl performs peer SSL certificate verification by default. This is done --by using a CA certificate store that the SSL library can use to make sure the --peer's server certificate is valid. -+curl does certificate verification by default. This is done by verifying the -+signature and making sure the certificate was crafted for the server name -+provided in the URL. - - If you communicate with HTTPS, FTPS or other TLS-using servers using --certificates in the CA store, you can be sure that the remote server really is --the one it claims to be. -+certificates signed by a CA whose certificate is present in the store, you can -+be sure that the remote server really is the one it claims to be. - --If the remote server uses a self-signed certificate, if you do not install a CA --cert store, if the server uses a certificate signed by a CA that is not -+If the remote server uses a self-signed certificate, if you do not install a -+CA cert store, if the server uses a certificate signed by a CA that is not - included in the store you use or if the remote host is an impostor --impersonating your favorite site, and you want to transfer files from this --server, do one of the following: -- -- 1. Tell libcurl to *not* verify the peer. With libcurl you disable this with -- `curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);` -- -- With the curl command line tool, you disable this with `-k`/`--insecure`. -- -- 2. Get a CA certificate that can verify the remote server and use the proper -- option to point out this CA cert for verification when connecting. For -- libcurl hackers: `curl_easy_setopt(curl, CURLOPT_CAINFO, cacert);` -- -- With the curl command line tool: `--cacert [file]` -- -- 3. Add the CA cert for your server to the existing default CA certificate -- store. The default CA certificate store can be changed at compile time with -- the following configure options: -- -- `--with-ca-bundle=FILE`: use the specified file as the CA certificate -- store. CA certificates need to be concatenated in PEM format into this -- file. -- -- `--with-ca-path=PATH`: use the specified path as CA certificate store. CA -- certificates need to be stored as individual PEM files in this directory. -- You may need to run c_rehash after adding files there. -- -- If neither of the two options is specified, configure tries to auto-detect -- a setting. It's also possible to explicitly not set any default store but -- rely on the built in default the crypto library may provide instead. You -- can achieve that by passing both `--without-ca-bundle` and -- `--without-ca-path` to the configure script. -- -- If you use Internet Explorer, this is one way to get extract the CA cert -- for a particular server: -- -- - View the certificate by double-clicking the padlock -- - Find out where the CA certificate is kept (Certificate> -- Authority Information Access>URL) -- - Get a copy of the crt file using curl -- - Convert it from crt to PEM using the OpenSSL tool: -- `openssl x509 -inform DES -in yourdownloaded.crt -out outcert.pem -text` -- - Add the `outcert.pem` to the CA certificate store or use it stand-alone -- as described below. -- -- If you use the `openssl` tool, this is one way to get extract the CA cert -- for a particular server: -- -- - `openssl s_client -showcerts -servername server -connect server:443 > cacert.pem` -- - type "quit", followed by the "ENTER" key -- - The certificate has `BEGIN CERTIFICATE` and `END CERTIFICATE` markers. -- - If you want to see the data in the certificate, you can do: `openssl -- x509 -inform PEM -in certfile -text -out certdata` where `certfile` is -- the cert you extracted from logfile. Look in `certdata`. -- - If you want to trust the certificate, you can add it to your CA -- certificate store or use it stand-alone as described. Just remember that -- the security is no better than the way you obtained the certificate. -- -- 4. If you are using the curl command line tool and the TLS backend is not -- Schannel then you can specify your own CA cert file by setting the -- environment variable `CURL_CA_BUNDLE` to the path of your choice. -- -- If you are using the curl command line tool on Windows, curl searches for -- a CA cert file named "curl-ca-bundle.crt" in these directories and in this -- order: -- 1. application's directory -- 2. current working directory -- 3. Windows System directory (e.g. C:\windows\system32) -- 4. Windows Directory (e.g. C:\windows) -- 5. all directories along %PATH% -- -- 5. Get another CA cert bundle. One option is to extract the one a recent -- Firefox browser uses by running 'make ca-bundle' in the curl build tree -- root, or possibly download a version that was generated this way for you: -- [CA Extract](https://curl.se/docs/caextract.html) -- --Neglecting to use one of the above methods when dealing with a server using a --certificate that is not signed by one of the certificates in the installed CA --certificate store, causes SSL to report an error (`certificate verify failed`) --during the handshake and SSL then refuses further communication with that --server. -- --Certificate Verification with Schannel and Secure Transport ------------------------------------------------------------- -- --If libcurl was built with Schannel (Microsoft's native TLS engine) or Secure --Transport (Apple's native TLS engine) support, then libcurl still performs --peer certificate verification, but instead of using a CA cert bundle, it uses --the certificates that are built into the OS. These are the same certificates --that appear in the Internet Options control panel (under Windows) or Keychain --Access application (under OS X). Any custom security rules for certificates --are honored. -+impersonating your favorite site, the certificate check fails and reports an -+error. -+ -+If you think it wrongly failed the verification, consider one of the following -+sections. -+ -+### Skip verification -+ -+Tell curl to *not* verify the peer with `-k`/`--insecure`. -+ -+We **strongly** recommend this is avoided and that even if you end up doing -+this for experimentation or development, **never** skip verification in -+production. -+ -+### Use a custom CA store -+ -+Get a CA certificate that can verify the remote server and use the proper -+option to point out this CA cert for verification when connecting - for this -+specific transfer only. -+ -+With the curl command line tool: `--cacert [file]` -+ -+If you use the curl command line tool without a native CA store, then you can -+specify your own CA cert file by setting the environment variable -+`CURL_CA_BUNDLE` to the path of your choice. -+ -+If you are using the curl command line tool on Windows, curl searches for a CA -+cert file named `curl-ca-bundle.crt` in these directories and in this order: -+ 1. application's directory -+ 2. current working directory -+ 3. Windows System directory (e.g. C:\Windows\System32) -+ 4. Windows Directory (e.g. C:\Windows) -+ 5. all directories along %PATH% -+ -+curl 8.11.0 added a build-time option to disable this search behavior, and -+another option to restrict search to the application's directory. -+ -+### Use the native store -+ -+In several environments, in particular on Windows, you can ask curl to use the -+system's native CA store when verifying the certificate. -+ -+With the curl command line tool: `--ca-native`. -+ -+### Modify the CA store -+ -+Add the CA cert for your server to the existing default CA certificate store. -+ -+Usually you can figure out the path to the local CA store by looking at the -+verbose output that `curl -v` shows when you connect to an HTTPS site. -+ -+### Change curl's default CA store -+ -+The default CA certificate store curl uses is set at build time. When you -+build curl you can point out your preferred path. -+ -+### Extract CA cert from a server -+ -+ curl -w %{certs} https://example.com > cacert.pem -+ -+The certificate has `BEGIN CERTIFICATE` and `END CERTIFICATE` markers. -+ -+### Get the Mozilla CA store -+ -+Download a version of the Firefox CA store converted to PEM format on the [CA -+Extract](https://curl.se/docs/caextract.html) page. It always features the -+latest Firefox bundle. -+ -+## Native CA store -+ -+If curl was built with Schannel, Secure Transport or were instructed to use -+the native CA Store, then curl uses the certificates that are built into the -+OS. These are the same certificates that appear in the Internet Options -+control panel (under Windows) or Keychain Access application (under macOS). -+Any custom security rules for certificates are honored. - - Schannel runs CRL checks on certificates unless peer verification is disabled. - Secure Transport on iOS runs OCSP checks on certificates unless peer --verification is disabled. Secure Transport on OS X runs either OCSP or CRL -+verification is disabled. Secure Transport on macOS runs either OCSP or CRL - checks on certificates if those features are enabled, and this behavior can be - adjusted in the preferences of Keychain Access. - --HTTPS proxy ------------- -+## HTTPS proxy - --Since version 7.52.0, curl can do HTTPS to the proxy separately from the --connection to the server. This TLS connection is handled separately from the --server connection so instead of `--insecure` and `--cacert` to control the -+curl can do HTTPS to the proxy separately from the connection to the server. -+This TLS connection is handled and verified separately from the server -+connection so instead of `--insecure` and `--cacert` to control the - certificate verification, you use `--proxy-insecure` and `--proxy-cacert`. - With these options, you make sure that the TLS connection and the trust of the - proxy can be kept totally separate from the TLS connection to the server. -diff --git a/docs/THANKS b/docs/THANKS -index 8bd6b3d86..959604bb9 100644 ---- a/docs/THANKS -+++ b/docs/THANKS -@@ -19,10 +19,12 @@ Aaron Oneal - Aaron Orenstein - Aaron Scarisbrick - aasivov on github -+Abdullah Alyan - Abhinav Singh - Abram Pousada - accountantM on github - AceCrow on Github -+ad-chaos on github - ad0p on github - Adam Averay - Adam Barclay -@@ -50,6 +52,7 @@ Ajit Dhumale - Akhil Kedia - Akhilesh Nema - Aki Koskinen -+Aki Sakurai - Akos Pasztory - Akshay Vernekar - Alain Danteny -@@ -67,6 +70,7 @@ Aleksandar Milivojevic - Aleksander Mazur - Aleksandr Krotov - Aleksey Tulinov -+alervd on github - Ales Mlakar - Ales Novak - Alessandro Ghedini -@@ -92,6 +96,7 @@ Alex Nichols - Alex Potapenko - Alex Rousskov - Alex Samorukov -+Alex Snast - Alex Suykov - Alex Vinnik - Alex Xu -@@ -108,6 +113,7 @@ Alexander Krasnostavsky - Alexander Lazic - Alexander Pepper - Alexander Peslyak -+Alexander Shtuchkin - Alexander Sinditskiy - Alexander Traud - Alexander V. Tikhonov -@@ -181,6 +187,7 @@ Andrei Sedoi - Andrei Valeriu BICA - Andrei Virtosu - Andrej E Baranov -+Andrew - Andrew Barnert - Andrew Barnes - Andrew Benham -@@ -207,6 +214,8 @@ Andrés García - Andy Alt - Andy Cedilnik - Andy Fiddaman -+Andy Pan -+Andy Reitz - Andy Serpa - Andy Stamp - Andy Tsouladze -@@ -225,6 +234,7 @@ Anthony Hu - Anthony Ramine - Anthony Shaw - Antoine Aubert -+Antoine Bollengier - Antoine Calando - Antoine du Hamel - Antoine Pietri -@@ -267,7 +277,9 @@ AtariDreams on github - Ates Goral - atjg on github - Augustus Saunders -+Aurélien Pierre - Austin Green -+Austin Moore - av223119 on github - Avery Fay - awesomekosm on github -@@ -337,6 +349,7 @@ Bertrand Demiddelaer - Bertrand Simonnet - beslick5 on github - Bevan Weiss -+Bhanu Prakash - Bill Doyle - Bill Egert - Bill Hoffman -@@ -357,6 +370,7 @@ Björn Stenberg - black-desk on github - Blaise Potard - Blake Burkhart -+blankie - bnfp on github - Bo Anderson - Bob Relyea -@@ -400,6 +414,7 @@ Brian Green - Brian Inglis - Brian J. Murrell - Brian Lund -+brian m. carlson - Brian Nixon - Brian Prodoehl - Brian R Duffy -@@ -440,6 +455,7 @@ Captain Basil - Carie Pointer - Carl Zogheib - Carlo Alberto -+Carlo Cabrera - Carlo Cannas - Carlo Marcelo Arenas Belón - Carlo Teubner -@@ -455,6 +471,7 @@ cbartl on github - cclauss on github - Cering on github - Cesar Eduardo Barros -+Ch40zz on github - Chad Monroe - Chandrakant Bagul - Chara White -@@ -485,6 +502,8 @@ Chris Paulson-Ellis - Chris Roberts - Chris Sauer - Chris Smowton -+Chris Stubbs -+Chris Swan - Chris Talbot - Chris Webb - Chris Young -@@ -492,6 +511,7 @@ Christian Fillion - Christian Grothoff - Christian Heimes - Christian Hesse -+Christian Heusel - Christian Hägele - Christian Krause - Christian Kurz -@@ -529,6 +549,7 @@ Clifford Wolf - Clint Clayton - Cloudogu Siebels - Clément Notin -+CMD - cmfrolick on github - codesniffer13 on github - Cody Jones -@@ -540,10 +561,12 @@ Colin Blair - Colin Cross - Colin Hogben - Colin Leroy -+Colin Leroy-Mira - Colin O'Dell - Colin Watson - Colm Buckley - Colman Mbuya -+Colton Willey - Constantine Sapuntzakis - consulion on github - coralw on github -@@ -573,6 +596,7 @@ d912e3 on github - Da-Yoon Chung - daboul on github - Dag Ekengren -+Dagfinn Ilmari Mannsåker - Dagobert Michelsen - Daiki Ueno - Dair Grant -@@ -604,6 +628,7 @@ Daniel Faust - Daniel Gustafsson - Daniel Hallberg - Daniel Hwang -+Daniel J. H. - Daniel Jeliński - Daniel Johnson - Daniel Kahn Gillmor -@@ -613,6 +638,7 @@ Daniel Kurečka - Daniel Lee Hwang - Daniel Lublin - Daniel Marjamäki -+Daniel McCarney - Daniel Melani - Daniel Mentz - Daniel Romero -@@ -678,6 +704,7 @@ David Phillips - David Rosenstrauch - David Ryskalczyk - David Sanderson -+David Sardari - David Schweikert - David Shaw - David Strauss -@@ -703,8 +730,10 @@ Denis Feklushkin - Denis Goleshchikhin - Denis Laxalde - Denis Ollier -+Deniz Sökmen - Dennis Clarke - Dennis Felsing -+dependabot[bot] - Derek Higgins - Derzsi Dániel - Desmond O. Chang -@@ -759,16 +788,19 @@ Dmitry S. Baikov - Dmitry Tretyakov - Dmitry Wagin - dnivras on github -+dogma - Dolbneff A.V - Domen Kožar - Domenico Andreoli - Dominick Meglio - Dominik Hölzl - Dominik Klemba -+Dominik Piątkowski - Dominik Thalhammer - Dominique Leuenberger - Don J Olmstead - Dongliang Mu -+Dorian Craps - Doron Behar - Doug Kaufman - Doug Porter -@@ -791,6 +823,7 @@ Dustin Howett - Dusty Mabe - Duy Phan Thanh - Dwarakanath Yadavalli -+Dylam De La Torre - Dylan Anthony - Dylan Ellicott - Dylan Salisbury -@@ -829,12 +862,15 @@ Eli Schwartz - Elia Tufarolo - Elliot Killick - Elliot Saba -+Elliott Balsley - Ellis Pritchard - Elmira A Semenova - Elms - Eloy Degen - elsamuko on github -+elvinasp on github - emanruse on github -+Emanuel Komínek - Emanuele Bovisio - Emanuele Torre - Emil Engler -@@ -862,6 +898,7 @@ Eric Melville - Eric Mertens - Eric Murphy - Eric Musser -+Eric Norris - Eric Rautman - Eric Rescorla - Eric Ridge -@@ -898,6 +935,7 @@ Evert Pot - Evgeny Grin (Karlson2k) - Evgeny Turnaev - eXeC64 on github -+extrimexxx on github - Eygene Ryabinkin - Eylem Ugurel - Fabian Fischer -@@ -912,6 +950,7 @@ Fabrizio Ammollo - Fahim Chandurwala - Faizur Rahman - Faraz Fallahi -+farazrbx on github - Farzin on github - Fata Nugraha - Fawad Mirza -@@ -921,6 +960,7 @@ Federico Bianchi - Federico Pellegrin - Fedor Karpelevitch - Fedor Korotkov -+feelingseas on github - FeignClaims on github - Feist Josselin - Felipe Gasper -@@ -974,9 +1014,11 @@ FuccDucc on github - Fujii Hironori - fullincome on github - fundawang on github -+fuzzard - Gabe - Gabriel Corona - Gabriel Kuri -+Gabriel Marin - Gabriel Simmer - Gabriel Sjoberg - Gaelan Steele -@@ -1033,8 +1075,10 @@ Glenn Sheridan - Glenn Strauss - godmar on github - Godwin Stewart -+Gonçalo Carvalho - Google Inc. - Gordon Marler -+Gordon Parke - Gorilla Maguila - Goro FUJI - Gou Lingfeng -@@ -1057,8 +1101,10 @@ Gregory Szorc - Griffin Downs - Grigory Entin - Grisha Levit -+Gruber Glass - Guenole Bescon - Guido Berhoerster -+Guilherme Puida - Guillaume Algis - Guillaume Arluison - guitared on github -@@ -1067,6 +1113,7 @@ Gunter Knauf - guoxinvmware on github - Gustaf Hui - Gustavo Grieco -+Gusted - Guy Poizat - GwanYeong Kim - Gwen Shapira -@@ -1079,6 +1126,7 @@ Hagai Auro - Haibo Huang - Hakan Sunay Halil - Hamish Mackenzie -+hammlee96 on github - hamstergene on github - Han Han - Han Qiao -@@ -1095,6 +1143,7 @@ Hans-Jurgen May - Hao Wu - Hardeep Singh - Haris Okanovic -+Harmen Stoppels - Harold Stuart - Harry Mallon - Harry Sarson -@@ -1130,6 +1179,7 @@ Hiroki Kurosawa - Hirotaka Tagawa - Ho-chi Chen - Hoi-Ho Chan -+Hongfei Li - Hongli Lai - Hongyi Zhao - Howard Blaise -@@ -1192,7 +1242,9 @@ Isaac Boukris - Isaiah Norton - Ishan SinghLevett - Ithubg on github -+Ivan - Ivan Avdeev -+Ivan Kuchin - Ivan Tsybulin - ivanfywang - IvanoG on github -@@ -1219,6 +1271,7 @@ Jakub Bochenski - Jakub Jelen - Jakub Wilk - Jakub Zakrzewski -+James Abbatiello - James Atwill - James Brown - James Bursa -@@ -1254,6 +1307,7 @@ Jan Venekamp - Jan Verbeek - Jan-Piet Mens - JanB on github -+janedenone on github - janko-js on github - Janne Blomqvist - Janne Johansson -@@ -1264,6 +1318,7 @@ Jari Sundell - jasal82 on github - Jason Baietto - Jason Glasgow -+Jason Hood - Jason Juang - Jason Lee - Jason Liu -@@ -1276,6 +1331,7 @@ Javier Navarro - Javier Sixto - Jay Austin - Jay Dommaschk -+Jay Guerette - Jay Wu - Jayesh A Shah - Jaz Fresh -@@ -1337,6 +1393,8 @@ Jesse Noller - Jesse Tan - jethrogb on github - jhoyla on github -+Jiacai Liu -+Jiang Wenjian - Jiawen Geng - Jie He - Jiehong on github -@@ -1353,12 +1411,15 @@ Jiri Dvorak - Jiri Hruska - Jiri Jaburek - Jishan Shaikh -+Jiwoo Park - Jiří Bok - Jiří Malák -+jkamp-aws on github - jmdavitt on github - jnbr on github - Jocelyn Jaubert - Jochem Broekhoff -+Joe Birr-Pixton - Joe Halpin - Joe Malicki - Joe Mason -@@ -1372,6 +1433,7 @@ Johan Anderson - Johan Lantz - Johan Nilsson - Johan van Selst -+Johann Sebastian Schicho - Johann150 on github - Johannes Bauer - Johannes Ernst -@@ -1431,6 +1493,7 @@ Jon Torrey - Jon Travis - Jon Turner - Jon Wilkes -+Jonas 'Sortie' Termansen - Jonas Bülow - Jonas Forsman - Jonas Haag -@@ -1441,6 +1504,7 @@ Jonatan Lander - Jonatan Vela - Jonathan Cardoso Machado - Jonathan Hseu -+Jonathan Matthews - Jonathan Moerman - Jonathan Nieder - Jonathan Perkin -@@ -1480,6 +1544,7 @@ Judson Bishop - Juergen Hoetzel - Juergen Wilke - Jukka Pihl -+Julian K. - Julian Montes - Julian Noble - Julian Ospald -@@ -1513,6 +1578,7 @@ jzinn on github - János Fekete - Jérémy Rabasco - Jérémy Rocher -+Jérôme Leclercq - Jörg Mueller-Tolk - Jörn Hartroth - Jürgen Gmach -@@ -1524,7 +1590,9 @@ Kai Noda - Kai Pastor - Kai Sommerfeld - Kai-Uwe Rommel -+Kailun Qin - Kalle Vahlman -+kalvdans on github - Kamil Dudka - Kane York - Kang Lin -@@ -1535,8 +1603,7 @@ Kari Pahula - Karl Chen - Karl Moerder - Karol Pietrzak --Kartatz on Github --Karthikdasari0423 -+Kartatz on github - Karthikdasari0423 on github - Kartik Mahajan - Kaspar Brand -@@ -1544,6 +1611,7 @@ Katie Wang - Katsuhiko YOSHIDA - Kazuho Oku - kchow-FTNT on github -+Keerthi Timmaraju - Kees Cook - Kees Dekker - Keitagit-kun on github -@@ -1581,6 +1649,7 @@ Kimmo Kinnunen - kirbyn17 on hackerone - Kirill Efimov - Kirill Marchuk -+kit-ty-kate on github - Kjell Ericson - Kjetil Jacobsen - Klaus Crusius -@@ -1592,12 +1661,14 @@ Koichi Shiraishi - kokke on github - Konstantin Isakov - Konstantin Kushnir -+Konstantin Kuzov - Konstantin Vlasov - KotlinIsland on github - kotoriのねこ -+koujaz on github - kouzhudong on github - Kovalkov Dmitrii --kpcyrd -+kpcyrd on github - kreshano on github - Kris Kennaway - Krishnendu Majumdar -@@ -1652,6 +1723,7 @@ Lawrence Wagerfield - Leah Neukirchen - Lealem Amedie - Leandro Coutinho -+Lee Li - LeeRiva - Legoff Vincent - Lehel Bernadt -@@ -1696,6 +1768,8 @@ Lluís Batlle i Rossell - locpyl-tidnyd on github - Loganaden Velvindron - Loic Dachary -+lolbinarycat on github -+lomberd2 on github - LoRd_MuldeR - Loren Kirkby - Lorenzo Miniero -@@ -1709,6 +1783,7 @@ Luca Niccoli - Lucas Adamski - Lucas Clemente Vella - Lucas Holt -+Lucas Nussbaum - Lucas Pardue - Lucas Servén Marín - Lucas Severo -@@ -1724,6 +1799,7 @@ Luke Amery - Luke Call - Luke Dashjr - Luke Granger-Brown -+Luke Hamburg - Lukáš Zaoral - luminixinc on github - Luo Jinghua -@@ -1738,8 +1814,10 @@ Maciej Domanski - Maciej Karpiuk - Maciej Puzio - Maciej W. Rozycki -+MacKenzie - madblobfish on github - MaeIsBad on github -+magisterquis on hackerone - Mahmoud Samir Fayed - Maks Naumov - Maksim Arhipov -@@ -1840,6 +1918,7 @@ Martin Jansen - Martin Kammerhofer - Martin Kepplinger - Martin Lemke -+Martin Peck - Martin Schmatz - Martin Skinner - Martin Staael -@@ -1849,8 +1928,10 @@ Martin V - Martin Vejnár - Martin Waleczek - Martin Ågren -+martinevsky - Marty Kuhrt - Maruko -+Marwan Yassini - Masaya Suzuki - masbug on github - Massimiliano Fantuzzi -@@ -1890,6 +1971,7 @@ Matthew Whitehead - Matthias Bolte - Matthias Gatto - Matthias Naegler -+Matthieu Baerts - Mattias Fornander - Matus Uzak - Maurice Barnum -@@ -1898,6 +1980,7 @@ Mauro Iorio - Mauro Rappa - Maurício Meneghini Fauth - Max Dymond -+Max Faxälv - Max Katsev - Max Kellermann - Max Khon -@@ -1917,11 +2000,12 @@ Median Median Stride - mehatzri on github - Mehmet Bozkurt - Mekonikum -+Mel Zuser - Melissa Mears - Melroy van den Berg - Mert Yazıcıoğlu - Mettgut Jamalla --Micah Snyder) -+Micah Snyder - Michael Afanasiev - Michael Anti - Michael Baentsch -@@ -1948,6 +2032,7 @@ Michael Kolechkin - Michael Kujawa - Michael König - Michael Lee -+Michael Litwak - Michael Maltese - Michael Mealling - Michael Mueller -@@ -2023,7 +2108,11 @@ Mohun Biswas - momala454 on github - Momoka Yamamoto - MonkeybreadSoftware on github -+Montg0mery on github - moohoorama on github -+Morgan Willcock -+Moritz Buhl -+Moritz Knüsel - Morten Minde Neergaard - Mostyn Bramley-Moore - Moti Avrahami -@@ -2062,11 +2151,13 @@ Neil Bowers - Neil Dunbar - Neil Kolban - Neil Spring -+nekopsykose on github -+Nemos2024 on github - neutric on github - nevv on HackerOne/curl -+newfunction - Niall McGee - Niall O'Reilly --niallor on github - nian6324 on github - nianxuejie on github - Nic Roets -@@ -2087,6 +2178,7 @@ nico-abram on github - Nicolas Berloquin - Nicolas Croiset - Nicolas François -+Nicolas George - Nicolas Grekas - Nicolas Guillier - Nicolas Morey-Chaisemartin -@@ -2148,6 +2240,7 @@ Oliver Schindler - Oliver Urbann - oliverpool on github - Olivier Berger -+Olivier Bonaventure - Olivier Brunel - Omar Ramadan - omau on github -@@ -2197,12 +2290,14 @@ Patrick Rapin - Patrick Schlangen - Patrick Scott - Patrick Smith -+Patrick Steinhardt - Patrick Watson - Patrik Thunstrom - Pau Garcia i Quiles - Paul B. Omta - Paul Donohue - Paul Dreik -+Paul Gilmartin - Paul Groke - Paul Harrington - Paul Harris -@@ -2224,6 +2319,7 @@ Paulo Roberto Tomasi - Pavel Cenek - Pavel Gushchin - Pavel Kalyugin -+Pavel Kropachev - Pavel Löbl - Pavel Mayorov - Pavel Orehov -@@ -2249,6 +2345,7 @@ Per Jensen - Per Lundberg - Per Malmberg - Per Nilsson -+Pete Cordell - Pete Lomax - Peter Bray - Peter Forret -@@ -2310,6 +2407,7 @@ Pierre Chapuis - Pierre Joye - Pierre Yager - Pierre Ynard -+Pierre-Etienne Meunier - Pierre-Yves Bigourdan - Pierrick Charron - Piotr Dobrogost -@@ -2352,6 +2450,7 @@ Rafael Sagula - Rafayel Mkrtchyan - Rafaël Carré - Rafał Mikrut -+Rahul Krishna M - Rainer Canavan - Rainer Jung - Rainer Koenig -@@ -2361,11 +2460,13 @@ Raito Bezarius - Rajesh Naganathan - Rajkumar Mandal - Ralf S. Engelschall -+ralfjunker on github - Ralph Beckmann - Ralph Langendam - Ralph Mitchell - Ram Krushna Mishra - Ramiro Garcia -+rampageX on github - ramsay-jones on github - Ran Mozes - RanBarLavie on github -@@ -2375,12 +2476,14 @@ Randy Armstrong - Randy McMurchy - Raphael Gozzo - Rasmus Melchior Jacobsen -+Rasmus Thomsen - Raul Onitza-Klugman - Ravi Pratap - Ray Dassen - Ray Pekowski - Ray Satiro - Razvan Cojocaru -+Razvan Pricope - rcombs on github - Red Hat Product Security - Reed Loden -@@ -2398,10 +2501,13 @@ Renaud Guillard - Renaud Lehoux - Rene Bernhardt - Rene Rebe -+renovate[bot] -+renovate[bot] - Reuven Wachtfogel - RevaliQaQ on github - Reza Arbab - Rianov Viacheslav -+riastradh on github - Ricardo Cadime - Ricardo Gomes - Ricardo M. Correia -@@ -2471,6 +2577,7 @@ Robert Foreman - Robert Iakobashvili - Robert Kolcun - Robert Linden -+Robert Maynard - Robert Moreton - Robert Olson - Robert Prag -@@ -2529,7 +2636,6 @@ Ruslan Gazizov - Rutger Broekhoff - Rutger Hofman - Ruurd Beerstra --RuurdBeerstra on github - rwmjones on github - Ryan Beck-Buysse - Ryan Braud -@@ -2556,6 +2662,7 @@ Salvatore Sorrentino - Sam Deane - Sam Hurst - Sam James -+Sam Jessup - Sam Roth - Sam Schanken - Samanta Navarro -@@ -2572,6 +2679,7 @@ SandakovMM on github - Sander Gates - Sandor Feldi - Sandro Jaeckel -+Sanjay Pujare - Santhana Todatry - Santino Keupp - Saqib Ali -@@ -2582,6 +2690,7 @@ Sascha Zengler - Satadru Pramanik - Satana de Sant'Ana - Saul good -+saurabhsingh-dev on github - Saurav Babu - sayrer on github - SBKarr on github -@@ -2601,12 +2710,14 @@ Sean McArthur - Sean Miller - Sean Molenaar - Sebastiaan van Erk -+Sebastian Andersson - Sebastian Haglund - Sebastian Mundry - Sebastian Neubauer - Sebastian Pohlschmidt - Sebastian Rasmussen - Sebastian Sterk -+Sebastian Walz - selmelc on hackerone - SendSonS on github - Senthil Raja Velu -@@ -2630,6 +2741,7 @@ Sergio Mijatovic - Sergio-IME on github - sergio-nsk on github - Serj Kalichev -+Sertonix - SerusDev on github - Seshubabu Pasam - Seth Mos -@@ -2672,9 +2784,10 @@ Simon Legner - Simon Liu - Simon Warta - simplerobot on github -+Sinkevich Artem - Siva Sivaraman -+Slaven Rezić - SLDiggie on github --Smackd0wn - Smackd0wn on github - smuellerDD on github - sn on hackerone -@@ -2683,6 +2796,7 @@ Sohom Datta - Somnath Kundu - Song Ma - Sonia Subramanian -+southernedge on github - Spacen Jasset - Spezifant on github - Spiridonoff A.V -@@ -2695,6 +2809,7 @@ Stadler Stephan - Stan Hu - Stan van de Burgt - Stanislav Ivochkin -+Stanislav Lange - Stanislav Zidek - Stanley Wucw - Stathis Kapnidis -@@ -2717,6 +2832,7 @@ Stefan Tomanek - Stefan Ulrich - Stefan Yohansson - Stefano Simonelli -+Steffen Kieß - Steinar H. Gunderson - steini2000 on github - Stepan Broz -@@ -2730,6 +2846,7 @@ Stephane Pellegrino - Stephen Boost - Stephen Brokenshire - Stephen Collyer -+Stephen Farrell - Stephen Kick - Stephen M. Coakley - Stephen More -@@ -2848,6 +2965,7 @@ Tim Stack - Tim Starling - Tim Tassonis - Tim Verhoeven -+Tim Yuer - Timmy Schierling - Timo Lange - Timo Sirainen -@@ -2862,6 +2980,7 @@ Tk Xiong - tlahn on github - tmkk on github - Tobias Blomberg -+Tobias Bora - Tobias Gabriel - Tobias Hieta - Tobias Hintze -@@ -2873,6 +2992,7 @@ Tobias Nyholm - Tobias Rundström - Tobias Schaefer - Tobias Stoeckmann -+Tobias Wendorff - Toby Peterson - Todd A Ouska - Todd Kaufmann -@@ -2911,10 +3031,12 @@ Tommy Chiang - Tommy Odom - Tommy Petty - Tommy Tam -+tomy2105 on github - Ton Voon - Toni Moreno - Tony Kelman - tonystz on Github -+Toon Claes - Toon Verwaest - Tor Arntsen - Torben Dannhauer -@@ -2931,6 +3053,8 @@ Trivikram Kamat - Troels Walsted Hansen - Troy Engel - trrui-huawei -+Trumeet on github -+Trzik on github - Tseng Jun - Tuomas Siipola - Tuomo Rinne -@@ -2962,14 +3086,17 @@ Vasiliy Ulyanov - Vasily Lobaskin - Vasy Okhin - Venkat Akella -+Venkat Krishna R - Venkataramana Mokkapati - Vicente Garcia -+Victor Kislov - Victor Magierski - Victor Snezhko - Victor Vieux - VictorVG on github - Vijay Panghal - Vikram Saxena -+Viktor Petersson - Viktor Szakats - Vilhelm Prytz - Ville Skyttä -@@ -2999,10 +3126,11 @@ Vojtech Janota - Vojtech Minarik - Vojtěch Král - Volker Schmid -+Vollstrecker on github - Vsevolod Novikov - vshmuk on hackerone - vulnerabilityspotter on hackerone --vvb2060 -+vuonganh1993 on github - vvb2060 on github - Vyron Tsingaras - Vítor Galvão -@@ -3043,6 +3171,7 @@ Wolf Vollprecht - Wouter Van Rooy - Wu Yongzheng - Wu Zheng -+wxiaoguang on github - Wyatt O'Day - Wyatt OʼDay - x2018 on github -@@ -3059,6 +3188,7 @@ XmiliaH on github - xnynx on github - xtonik on github - xwxbug on github -+XYenon - Xì Gà - Yaakov Selkowitz - Yadhu Krishna M -@@ -3081,6 +3211,7 @@ yiyuaner on github - Ymir1711 on github - Yonggang Luo - Yongkang Huang -+Yoshimasa Ohno - Younes El-karama - youngchopin on github - Yousuke Kimoto -@@ -3096,8 +3227,7 @@ Yusuke Nakamura - Yves Arrouye - Yves Lejeune - YX Hao --z2-2z on github --z2_ on hackerone -+z2_ - Zachary Seguin - Zdenek Pavlas - Zekun Ni -@@ -3116,7 +3246,9 @@ Zhibiao Wu - zhihaoy on github - Zhouyihai Ding - ZimCodes on github -+zjyhjqs - zloi-user on github -+zmcx16 on github - Zmey Petroff - Zvi Har'El - zzq1015 on github -@@ -3128,11 +3260,14 @@ zzq1015 on github - Štefan Kremeň - Борис Верховский - Коваленко Анатолий Викторович -+наб - Никита Дорохин - ウさん - 不确定 - 加藤郁之 - 南宫雪珊 - 左潇峰 -+李四 - 梦终无痕 - 積丹尼 Dan Jacobson -+罗朝辉 -diff --git a/docs/THANKS-filter b/docs/THANKS-filter -index 732ccfe74..74676e711 100644 ---- a/docs/THANKS-filter -+++ b/docs/THANKS-filter -@@ -137,3 +137,20 @@ s/Dan Fandrich\./Dan Fandrich/ - s/GitHub$// - s/pszlazak$/pszlazak on github/ - s/Randall$/Randall S. Becker/ -+s/talregev on github/Tal Regev/ -+s/daniel-j-h/Daniel J. H./ -+s/hongfei.li/Hongfei Li/ -+s/z2_ on hackerone/z2_/ -+s/z2-2z on github/z2_/ -+s/janedenone on hackerone/janedenone on github/ -+s/Benjamin Riefenstahl Mecom/Benjamin Riefenstahl/ -+s/Micah Snyder)/Micah Snyder/ -+s/\#14922// -+s/vvb2060\z/vvb2060 on github/ -+s/kartatz\z/Kartatz on github/i -+s/Karthikdasari0423\z/Karthikdasari0423 on github/ -+s/niallor on github/Niall O'Reilly/ -+s/RuurdBeerstra on github/Ruurd Beerstra/ -+s/Smackd0wn\z/Smackd0wn on github/ -+s/Testclutch// -+s/edmcln\z/edmcln on github/ -diff --git a/docs/TODO b/docs/TODO -index 159e2e875..b8d1f4191 100644 ---- a/docs/TODO -+++ b/docs/TODO -@@ -20,15 +20,16 @@ - 1.1 TFO support on Windows - 1.2 Consult %APPDATA% also for .netrc - 1.3 struct lifreq -- 1.4 Better and more sharing -+ 1.4 alt-svc sharing - 1.5 get rid of PATH_MAX -- 1.6 native IDN support on macOS -+ 1.6 thread-safe sharing - 1.8 CURLOPT_RESOLVE for any port number - 1.9 Cache negative name resolves - 1.10 auto-detect proxy - 1.11 minimize dependencies with dynamically loaded modules - 1.12 updated DNS server while running - 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION -+ 1.14 connect to multiple IPs in parallel - 1.15 Monitor connections in the connection pool - 1.16 Try to URL encode given URL - 1.17 Add support for IRIs -@@ -58,14 +59,10 @@ - - 3. Documentation - 3.1 Improve documentation about fork safety -- 3.2 Provide cmake config-file - - 4. FTP - 4.1 HOST -- 4.2 Alter passive/active on failure and retry -- 4.3 Earlier bad letter detection -- 4.4 Support CURLOPT_PREQUOTE for dir listings too -- 4.5 ASCII support -+ 4.4 Support CURLOPT_PREQUOTE for directories listings - 4.6 GSSAPI via Windows SSPI - 4.7 STAT for LIST without data connection - 4.8 Passive transfer could try other IP addresses -@@ -95,6 +92,7 @@ - - 9. IMAP - 9.1 Enhanced capability support -+ 9.2 upload unread - - 10. LDAP - 10.1 SASL based authentication mechanisms -@@ -109,13 +107,12 @@ - 11.4 Create remote directories - - 12. FILE -- 12.1 Directory listing for FILE: -+ 12.1 Directory listing on non-POSIX - - 13. TLS - 13.1 TLS-PSK with OpenSSL -- 13.2 Provide mutex locking API -+ 13.2 TLS channel binding - 13.3 Defeat TLS fingerprinting -- 13.4 Cache/share OpenSSL contexts - 13.5 Export session ids - 13.6 Provide callback for cert verification - 13.7 Less memory massaging with Schannel -@@ -123,13 +120,11 @@ - 13.9 TLS record padding - 13.10 Support Authority Information Access certificate extension (AIA) - 13.11 Some TLS options are not offered for HTTPS proxies -- 13.12 Reduce CA certificate bundle reparsing - 13.13 Make sure we forbid TLS 1.3 post-handshake authentication - 13.14 Support the clienthello extension - 13.15 Select signature algorithms -- -- 14. GnuTLS -- 14.2 check connection -+ 13.16 Share the CA cache -+ 13.17 Add missing features to TLS backends - - 15. Schannel - 15.1 Extend support for client certificate authentication -@@ -154,25 +149,25 @@ - 18.4 --proxycommand - 18.5 UTF-8 filenames in Content-Disposition - 18.6 Option to make -Z merge lined based outputs on stdout -- 18.8 Consider convenience options for JSON and XML? -+ 18.7 specify which response codes that make -f/--fail return error - 18.9 Choose the name of file in braces for complex URLs -- 18.10 improve how curl works in a windows console window -+ 18.10 improve how curl works in a Windows console window - 18.11 Windows: set attribute 'archive' for completed downloads - 18.12 keep running, read instructions from pipe/socket -- 18.13 Ratelimit or wait between serial requests -+ 18.13 Acknowledge Ratelimit headers - 18.14 --dry-run - 18.15 --retry should resume - 18.16 send only part of --data -- 18.17 consider file name from the redirected URL with -O ? -+ 18.17 consider filename from the redirected URL with -O ? - 18.18 retry on network is unreachable - 18.19 expand ~/ in config files -- 18.20 host name sections in config files -+ 18.20 hostname sections in config files - 18.21 retry on the redirected-to URL - 18.23 Set the modification date on an uploaded file - 18.24 Use multiple parallel transfers for a single download - 18.25 Prevent terminal injection when writing to terminal - 18.26 Custom progress meter update interval -- 18.27 -J and -O with %-encoded file names -+ 18.27 -J and -O with %-encoded filenames - 18.28 -J with -C - - 18.29 --retry and transfer timeouts - -@@ -181,23 +176,25 @@ - 19.3 Do not use GNU libtool on OpenBSD - 19.4 Package curl for Windows in a signed installer - 19.5 make configure use --cache-file more and better -- 19.6 build curl with Windows Unicode support - - 20. Test suite - 20.1 SSL tunnel - 20.2 nicer lacking perl message - 20.3 more protocols supported - 20.4 more platforms supported -- 20.5 Add support for concurrent connections - 20.6 Use the RFC 6265 test suite -- 20.7 Support LD_PRELOAD on macOS - 20.8 Run web-platform-tests URL tests - - 21. MQTT - 21.1 Support rate-limiting -+ 21.2 Support MQTTS -+ 21.3 Handle network blocks - - 22. TFTP -- 22.1 TFTP doesn't convert LF to CRLF for mode=netascii -+ 22.1 TFTP does not convert LF to CRLF for mode=netascii -+ -+ 23. Gopher -+ 23.1 Handle network blocks - - ============================================================================== - -@@ -206,7 +203,7 @@ - 1.1 TFO support on Windows - - libcurl supports the CURLOPT_TCP_FASTOPEN option since 7.49.0 for Linux and -- Mac OS. Windows supports TCP Fast Open starting with Windows 10, version 1607 -+ macOS. Windows supports TCP Fast Open starting with Windows 10, version 1607 - and we should add support for it. - - TCP Fast Open is supported on several platforms but not on Windows. Work on -@@ -226,7 +223,7 @@ - SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete. - To support IPv6 interface addresses for network interfaces properly. - --1.4 Better and more sharing -+1.4 alt-svc sharing - - The share interface could benefit from allowing the alt-svc cache to be - possible to share between easy handles. -@@ -251,21 +248,18 @@ - there we need libssh2 to properly tell us when we pass in a too small buffer - and its current API (as of libssh2 1.2.7) does not. - --1.6 native IDN support on macOS -- -- On recent macOS versions, the getaddrinfo() function itself has built-in IDN -- support. By setting the AI_CANONNAME flag, the function will return the -- encoded name in the ai_canonname struct field in the returned information. -- This could be used by curl on macOS when built without a separate IDN library -- and an IDN host name is used in a URL. -+1.6 thread-safe sharing - -- See initial work in https://github.com/curl/curl/pull/5371 -+ Using the share interface users can share some data between easy handles but -+ several of the sharing options are documented as not safe and supported to -+ share between multiple concurrent threads. Fixing this would enable more -+ users to share data in more powerful ways. - - 1.8 CURLOPT_RESOLVE for any port number - - This option allows applications to set a replacement IP address for a given - host + port pair. Consider making support for providing a replacement address -- for the host name on all port numbers. -+ for the hostname on all port numbers. - - See https://github.com/curl/curl/issues/1264 - -@@ -306,14 +300,26 @@ - - 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION - -- curl will create most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and -+ curl creates most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and - close them with the CURLOPT_CLOSESOCKETFUNCTION callback. However, c-ares -- does not use those functions and instead opens and closes the sockets -- itself. This means that when curl passes the c-ares socket to the -- CURLMOPT_SOCKETFUNCTION it is not owned by the application like other sockets. -+ does not use those functions and instead opens and closes the sockets itself. -+ This means that when curl passes the c-ares socket to the -+ CURLMOPT_SOCKETFUNCTION it is not owned by the application like other -+ sockets. - - See https://github.com/curl/curl/issues/2734 - -+1.14 connect to multiple IPs in parallel -+ -+ curl currently implements the happy eyeball algorithm for connecting to the -+ IPv4 and IPv6 alternatives for a host in parallel, sticking with the -+ connection that "wins". We could implement a similar algorithm per individual -+ IP family as well when there are multiple available addresses: start with the -+ first address, then start a second attempt N milliseconds after and then a -+ third another N milliseconds later. That way there would be less waiting when -+ the first IP has problems. It also improves the connection timeout value -+ handling for multiple address situations. -+ - 1.15 Monitor connections in the connection pool - - libcurl's connection cache or pool holds a number of open connections for the -@@ -340,7 +346,7 @@ - - 1.17 Add support for IRIs - -- IRIs (RFC 3987) allow localized, non-ascii, names in the URL. To properly -+ IRIs (RFC 3987) allow localized, non-ASCII, names in the URL. To properly - support this, curl/libcurl would need to translate/encode the given input - from the input string encoding into percent encoded output "over the wire". - -@@ -460,7 +466,7 @@ - Make sure we do not ever loop because of non-blocking sockets returning - EWOULDBLOCK or similar. Blocking cases include: - -- - Name resolves on non-windows unless c-ares or the threaded resolver is used. -+ - Name resolves on non-Windows unless c-ares or the threaded resolver is used. - - - The threaded resolver may block on cleanup: - https://github.com/curl/curl/issues/4852 -@@ -476,6 +482,8 @@ - - - curl_multi_remove_handle for any of the above. See section 2.3. - -+ - Calling curl_ws_send() from a callback -+ - 2.2 Better support for same name resolves - - If a name resolve has been initiated for name NN and a second easy handle -@@ -496,8 +504,8 @@ - 2.4 Split connect and authentication process - - The multi interface treats the authentication process as part of the connect -- phase. As such any failures during authentication will not trigger the relevant -- QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP. -+ phase. As such any failures during authentication does not trigger the -+ relevant QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP. - - 2.5 Edge-triggered sockets should work - -@@ -537,45 +545,22 @@ - - See https://github.com/curl/curl/issues/6968 - --3.2 Provide cmake config-file -- -- A config-file package is a set of files provided by us to allow applications -- to write cmake scripts to find and use libcurl easier. See -- https://github.com/curl/curl/issues/885 -- - 4. FTP - - 4.1 HOST - -- HOST is a command for a client to tell which host name to use, to offer FTP -+ HOST is a command for a client to tell which hostname to use, to offer FTP - servers named-based virtual hosting: - - https://datatracker.ietf.org/doc/html/rfc7151 - --4.2 Alter passive/active on failure and retry -- -- When trying to connect passively to a server which only supports active -- connections, libcurl returns CURLE_FTP_WEIRD_PASV_REPLY and closes the -- connection. There could be a way to fallback to an active connection (and -- vice versa). https://curl.se/bug/feature.cgi?id=1754793 -- --4.3 Earlier bad letter detection -- -- Make the detection of (bad) %0d and %0a codes in FTP URL parts earlier in the -- process to avoid doing a resolve and connect in vain. -- --4.4 Support CURLOPT_PREQUOTE for dir listings too -+4.4 Support CURLOPT_PREQUOTE for directions listings - - The lack of support is mostly an oversight and requires the FTP state machine - to get updated to get fixed. - - https://github.com/curl/curl/issues/8602 - --4.5 ASCII support -- -- FTP ASCII transfers do not follow RFC 959. They do not convert the data -- accordingly. -- - 4.6 GSSAPI via Windows SSPI - - In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5) -@@ -605,10 +590,10 @@ - - 5.1 Provide the error body from a CONNECT response - -- When curl receives a body response from a CONNECT request to a proxy, it will -- always just read and ignore it. It would make some users happy if curl -- instead optionally would be able to make that responsible available. Via a new -- callback? Through some other means? -+ When curl receives a body response from a CONNECT request to a proxy, it -+ always just reads and ignores it. It would make some users happy if curl -+ instead optionally would be able to make that responsible available. Via a -+ new callback? Through some other means? - - See https://github.com/curl/curl/issues/9513 - -@@ -635,7 +620,7 @@ - 5.4 Allow SAN names in HTTP/2 server push - - curl only allows HTTP/2 push promise if the provided :authority header value -- exactly matches the host name given in the URL. It could be extended to allow -+ exactly matches the hostname given in the URL. It could be extended to allow - any name that would match the Subject Alternative Names in the server's TLS - certificate. - -@@ -680,7 +665,7 @@ - 6.2 ditch telnet-specific select - - Move the telnet support's network select() loop go away and merge the code -- into the main transfer loop. Until this is done, the multi interface will not -+ into the main transfer loop. Until this is done, the multi interface does not - work for telnet. - - 6.3 feature negotiation debug data -@@ -735,6 +720,12 @@ - Add the ability, for an application that uses libcurl, to obtain the list of - capabilities returned from the CAPABILITY command. - -+9.2 upload unread -+ -+ Uploads over IMAP currently always set the email as "read" (or "seen"). It -+ would be good to offer a way for users to select for uploads to remain -+ unread. -+ - 10. LDAP - - 10.1 SASL based authentication mechanisms -@@ -758,7 +749,7 @@ - - 10.4 Certificate-Based Authentication - -- LDAPS not possible with MAC and Windows with Certificate-Based Authentication -+ LDAPS not possible with macOS and Windows with Certificate-Based Authentication - - https://github.com/curl/curl/issues/9641 - -@@ -786,11 +777,11 @@ - - 12. FILE - --12.1 Directory listing for FILE: -- -- Add support for listing the contents of a directory accessed with FILE. The -- output should probably be the same as/similar to FTP. -+12.1 Directory listing on non-POSIX - -+ Listing the contents of a directory accessed with FILE only works on -+ platforms with opendir. Support could be added for more systems, like -+ Windows. - - 13. TLS - -@@ -803,11 +794,22 @@ - - https://github.com/curl/curl/issues/5081 - --13.2 Provide mutex locking API -+13.2 TLS channel binding -+ -+ TLS 1.2 and 1.3 provide the ability to extract some secret data from the TLS -+ connection and use it in the client request (usually in some sort of -+ authentication) to ensure that the data sent is bound to the specific TLS -+ connection and cannot be successfully intercepted by a proxy. This -+ functionality can be used in a standard authentication mechanism such as -+ GSS-API or SCRAM, or in custom approaches like custom HTTP Authentication -+ headers. - -- Provide a libcurl API for setting mutex callbacks in the underlying SSL -- library, so that the same application code can use mutex-locking -- independently of OpenSSL or GnutTLS being used. -+ For TLS 1.2, the binding type is usually tls-unique, and for TLS 1.3 it is -+ tls-exporter. -+ -+ https://datatracker.ietf.org/doc/html/rfc5929 -+ https://datatracker.ietf.org/doc/html/rfc9266 -+ https://github.com/curl/curl/issues/9226 - - 13.3 Defeat TLS fingerprinting - -@@ -815,24 +817,6 @@ - sometimes possible to circumvent TLS fingerprinting by servers. The TLS - extension order is of course not the only way to fingerprint a client. - -- See https://github.com/curl/curl/issues/8119 -- --13.4 Cache/share OpenSSL contexts -- -- "Look at SSL cafile - quick traces look to me like these are done on every -- request as well, when they should only be necessary once per SSL context (or -- once per handle)". The major improvement we can rather easily do is to make -- sure we do not create and kill a new SSL "context" for every request, but -- instead make one for every connection and reuse that SSL context in the same -- style connections are reused. It will make us use slightly more memory but it -- will libcurl do less creations and deletions of SSL contexts. -- -- Technically, the "caching" is probably best implemented by getting added to -- the share interface so that easy handles who want to and can reuse the -- context specify that by sharing with the right properties set. -- -- https://github.com/curl/curl/issues/1110 -- - 13.5 Export session ids - - Add an interface to libcurl that enables "session IDs" to get -@@ -898,15 +882,6 @@ - - https://github.com/curl/curl/issues/12286 - --13.12 Reduce CA certificate bundle reparsing -- -- When using the OpenSSL backend, curl will load and reparse the CA bundle at -- the creation of the "SSL context" when it sets up a connection to do a TLS -- handshake. A more effective way would be to somehow cache the CA bundle to -- avoid it having to be repeatedly reloaded and reparsed. -- -- See https://github.com/curl/curl/issues/9379 -- - 13.13 Make sure we forbid TLS 1.3 post-handshake authentication - - RFC 8740 explains how using HTTP/2 must forbid the use of TLS 1.3 -@@ -932,12 +907,18 @@ - - https://github.com/curl/curl/issues/12982 - --14. GnuTLS -+13.16 Share the CA cache -+ -+ For TLS backends that supports CA caching, it makes sense to allow the share -+ object to be used to store the CA cache as well via the share API. Would -+ allow multiple easy handles to reuse the CA cache and save themselves from a -+ lot of extra processing overhead. - --14.2 check connection -+13.17 Add missing features to TLS backends - -- Add a way to check if the connection seems to be alive, to correspond to the -- SSL_peak() way we use with OpenSSL. -+ The feature matrix at https://curl.se/libcurl/c/tls-options.html shows which -+ features are supported by which TLS backends, and thus also where there are -+ feature gaps. - - 15. Schannel - -@@ -957,10 +938,10 @@ - - 15.4 Add option to allow abrupt server closure - -- libcurl w/schannel will error without a known termination point from the -- server (such as length of transfer, or SSL "close notify" alert) to prevent -- against a truncation attack. Really old servers may neglect to send any -- termination point. An option could be added to ignore such abrupt closures. -+ libcurl with Schannel errors without a known termination point from the server -+ (such as length of transfer, or SSL "close notify" alert) to prevent against -+ a truncation attack. Really old servers may neglect to send any termination -+ point. An option could be added to ignore such abrupt closures. - - https://github.com/curl/curl/issues/4427 - -@@ -986,7 +967,7 @@ - SSH is a perfectly fine multiplexed protocols which would allow libcurl to do - multiple parallel transfers from the same host using the same connection, - much in the same spirit as HTTP/2 does. libcurl however does not take -- advantage of that ability but will instead always create a new connection for -+ advantage of that ability but does instead always create a new connection for - new transfers even if an existing connection already exists to the host. - - To fix this, libcurl would have to detect an existing connection and "attach" -@@ -996,7 +977,7 @@ - - The SFTP code in libcurl checks the file size *before* a transfer starts and - then proceeds to transfer exactly that amount of data. If the remote file -- grows while the transfer is in progress libcurl will not notice and will not -+ grows while the transfer is in progress libcurl does not notice and does not - adapt. The OpenSSH SFTP command line tool does and libcurl could also just - attempt to download more to see if there is more to get... - -@@ -1064,24 +1045,15 @@ - 18.6 Option to make -Z merge lined based outputs on stdout - - When a user requests multiple lined based files using -Z and sends them to -- stdout, curl will not "merge" and send complete lines fine but may send -+ stdout, curl does not "merge" and send complete lines fine but may send - partial lines from several sources. - - https://github.com/curl/curl/issues/5175 - --18.8 Consider convenience options for JSON and XML? -- -- Could we add `--xml` or `--json` to add headers needed to call rest API: -+18.7 specify which response codes that make -f/--fail return error - -- `--xml` adds -H 'Content-Type: application/xml' -H "Accept: application/xml" and -- `--json` adds -H 'Content-Type: application/json' -H "Accept: application/json" -- -- Setting Content-Type when doing a GET or any other method without a body -- would be a bit strange I think - so maybe only add CT for requests with body? -- Maybe plain `--xml` and ` --json` are a bit too brief and generic. Maybe -- `--http-json` etc? -- -- See https://github.com/curl/curl/issues/5203 -+ Allows a user to better specify exactly which error code(s) that are fine -+ and which are errors for their specific uses cases - - 18.9 Choose the name of file in braces for complex URLs - -@@ -1095,7 +1067,7 @@ - - See https://github.com/curl/curl/issues/221 - --18.10 improve how curl works in a windows console window -+18.10 improve how curl works in a Windows console window - - If you pull the scrollbar when transferring with curl in a Windows console - window, the transfer is interrupted and can get disconnected. This can -@@ -1107,7 +1079,7 @@ - backed up from those that are either not ready or have not changed. - - Downloads in progress are neither ready to be backed up, nor should they be -- opened by a different process. Only after a download has been completed it's -+ opened by a different process. Only after a download has been completed it is - sensible to include it in any integer snapshot or backup of the system. - - See https://github.com/curl/curl/issues/3354 -@@ -1120,12 +1092,10 @@ - invoke can talk to the still running instance and ask for transfers to get - done, and thus maintain its connection pool, DNS cache and more. - --18.13 Ratelimit or wait between serial requests -+18.13 Acknowledge Ratelimit headers - - Consider a command line option that can make curl do multiple serial requests -- slow, potentially with a (random) wait between transfers. There is also a -- proposed set of standard HTTP headers to let servers let the client adapt to -- its rate limits: -+ while acknowledging server specified rate limits: - https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/ - - See https://github.com/curl/curl/issues/5406 -@@ -1155,22 +1125,22 @@ - - See https://github.com/curl/curl/issues/1200 - --18.17 consider file name from the redirected URL with -O ? -+18.17 consider filename from the redirected URL with -O ? - - When a user gives a URL and uses -O, and curl follows a redirect to a new -- URL, the file name is not extracted and used from the newly redirected-to URL -- even if the new URL may have a much more sensible file name. -+ URL, the filename is not extracted and used from the newly redirected-to URL -+ even if the new URL may have a much more sensible filename. - - This is clearly documented and helps for security since there is no surprise -- to users which file name that might get overwritten. But maybe a new option -+ to users which filename that might get overwritten, but maybe a new option - could allow for this or maybe -J should imply such a treatment as well as -J -- already allows for the server to decide what file name to use so it already -+ already allows for the server to decide what filename to use so it already - provides the "may overwrite any file" risk. - -- This is extra tricky if the original URL has no file name part at all since -- then the current code path will error out with an error message, and we cannot -- *know* already at that point if curl will be redirected to a URL that has a -- file name... -+ This is extra tricky if the original URL has no filename part at all since -+ then the current code path does error out with an error message, and we -+ cannot *know* already at that point if curl is redirected to a URL that has a -+ filename... - - See https://github.com/curl/curl/issues/1241 - -@@ -1192,10 +1162,10 @@ - - See https://github.com/curl/curl/issues/2317 - --18.20 host name sections in config files -+18.20 hostname sections in config files - - config files would be more powerful if they could set different -- configurations depending on used URLs, host name or possibly origin. Then a -+ configurations depending on used URLs, hostname or possibly origin. Then a - default .curlrc could a specific user-agent only when doing requests against - a certain site. - -@@ -1233,7 +1203,7 @@ - - If splitting up the work improves the transfer rate, it could then be done - again. Then again, etc up to a limit. - -- This way, if transfer B fails (because Range: is not supported) it will let -+ This way, if transfer B fails (because Range: is not supported) it lets - transfer A remain the single one. N and M could be set to some sensible - defaults. - -@@ -1254,11 +1224,11 @@ - progressing and has not stuck, but they may not appreciate the - many-times-a-second frequency curl can end up doing it with now. - --18.27 -J and -O with %-encoded file names -+18.27 -J and -O with %-encoded filenames - -- -J/--remote-header-name does not decode %-encoded file names. RFC 6266 details -+ -J/--remote-header-name does not decode %-encoded filenames. RFC 6266 details - how it should be done. The can of worm is basically that we have no charset -- handling in curl and ascii >=128 is a challenge for us. Not to mention that -+ handling in curl and ASCII >=128 is a challenge for us. Not to mention that - decoding also means that we need to check for nastiness that is attempted, - like "../" sequences and the like. Probably everything to the left of any - embedded slashes should be cut off. -@@ -1267,15 +1237,15 @@ - -O also does not decode %-encoded names, and while it has even less - information about the charset involved the process is similar to the -J case. - -- Note that we will not add decoding to -O without the user asking for it with -- some other means as well, since -O has always been documented to use the name -- exactly as specified in the URL. -+ Note that we do not decode -O without the user asking for it with some other -+ means, since -O has always been documented to use the name exactly as -+ specified in the URL. - - 18.28 -J with -C - - - When using -J (with -O), automatically resumed downloading together with "-C - -" fails. Without -J the same command line works. This happens because the -- resume logic is worked out before the target file name (and thus its -+ resume logic is worked out before the target filename (and thus its - pre-transfer size) has been figured out. This can be improved. - - https://curl.se/bug/view.cgi?id=1169 -@@ -1284,8 +1254,8 @@ - - If using --retry and the transfer timeouts (possibly due to using -m or - -y/-Y) the next attempt does not resume the transfer properly from what was -- downloaded in the previous attempt but will truncate and restart at the -- original position where it was at before the previous failed attempt. See -+ downloaded in the previous attempt but truncates and restarts at the original -+ position where it was at before the previous failed attempt. See - https://curl.se/mail/lib-2008-01/0080.html and Mandriva bug report - https://qa.mandriva.com/show_bug.cgi?id=22565 - -@@ -1305,12 +1275,13 @@ - curl. - - 19.3 Do not use GNU libtool on OpenBSD -- When compiling curl on OpenBSD with "--enable-debug" it will give linking -- errors when you use GNU libtool. This can be fixed by using the libtool -- provided by OpenBSD itself. However for this the user always needs to invoke -- make with "LIBTOOL=/usr/bin/libtool". It would be nice if the script could -- have some magic to detect if this system is an OpenBSD host and then use the -- OpenBSD libtool instead. -+ -+ When compiling curl on OpenBSD with "--enable-debug" it gives linking errors -+ when you use GNU libtool. This can be fixed by using the libtool provided by -+ OpenBSD itself. However for this the user always needs to invoke make with -+ "LIBTOOL=/usr/bin/libtool". It would be nice if the script could have some -+ magic to detect if this system is an OpenBSD host and then use the OpenBSD -+ libtool instead. - - See https://github.com/curl/curl/issues/5862 - -@@ -1325,13 +1296,6 @@ - - See https://github.com/curl/curl/issues/7753 - --19.6 build curl with Windows Unicode support -- -- The user wants an easier way to tell autotools to build curl with Windows -- Unicode support, like ./configure --enable-windows-unicode -- -- See https://github.com/curl/curl/issues/7229 -- - 20. Test suite - - 20.1 SSL tunnel -@@ -1352,38 +1316,18 @@ - - 20.4 more platforms supported - -- Make the test suite work on more platforms. OpenBSD and Mac OS. Remove -+ Make the test suite work on more platforms. OpenBSD and macOS. Remove - fork()s and it should become even more portable. - --20.5 Add support for concurrent connections -- -- Tests 836, 882 and 938 were designed to verify that separate connections are -- not used when using different login credentials in protocols that should not -- reuse a connection under such circumstances. -- -- Unfortunately, ftpserver.pl does not appear to support multiple concurrent -- connections. The read while() loop seems to loop until it receives a -- disconnect from the client, where it then enters the waiting for connections -- loop. When the client opens a second connection to the server, the first -- connection has not been dropped (unless it has been forced - which we -- should not do in these tests) and thus the wait for connections loop is never -- entered to receive the second connection. -- - 20.6 Use the RFC 6265 test suite - - A test suite made for HTTP cookies (RFC 6265) by Adam Barth is available at - https://github.com/abarth/http-state/tree/master/tests - -- It'd be really awesome if someone would write a script/setup that would run -- curl with that test suite and detect deviances. Ideally, that would even be -+ It would be good if someone would write a script/setup that would run curl -+ with that test suite and detect deviances. Ideally, that would even be - incorporated into our regular test suite. - --20.7 Support LD_PRELOAD on macOS -- -- LD_RELOAD does not work on macOS, but there are tests which require it to run -- properly. Look into making the preload support in runtests.pl portable such -- that it uses DYLD_INSERT_LIBRARIES on macOS. -- - 20.8 Run web-platform-tests URL tests - - Run web-platform-tests URL tests and compare results with browsers on wpt.fyi -@@ -1400,9 +1344,17 @@ - The rate-limiting logic is done in the PERFORMING state in multi.c but MQTT - is not (yet) implemented to use that. - -+21.2 Support MQTTS -+ -+21.3 Handle network blocks -+ -+ Running test suite with -+ `CURL_DBG_SOCK_WBLOCK=90 ./runtests.pl -a mqtt` makes several -+ MQTT test cases fail where they should not. -+ - 22. TFTP - --22.1 TFTP doesn't convert LF to CRLF for mode=netascii -+22.1 TFTP does not convert LF to CRLF for mode=netascii - - RFC 3617 defines that an TFTP transfer can be done using "netascii" - mode. curl does not support extracting that mode from the URL nor does it treat -@@ -1410,3 +1362,11 @@ - for them. - - See https://github.com/curl/curl/issues/12655 -+ -+23. Gopher -+ -+23.1 Handle network blocks -+ -+ Running test suite with -+ `CURL_DBG_SOCK_WBLOCK=90 ./runtests.pl -a 1200 to 1300` makes several -+ Gopher test cases fail where they should not. -diff --git a/docs/TheArtOfHttpScripting.md b/docs/TheArtOfHttpScripting.md -index 4e111a3e3..f4efd11bb 100644 ---- a/docs/TheArtOfHttpScripting.md -+++ b/docs/TheArtOfHttpScripting.md -@@ -1,3 +1,9 @@ -+ -+ - # The Art Of Scripting HTTP Requests Using Curl - - ## Background -@@ -565,19 +571,19 @@ - - Curl supports encrypted fetches when built to use a TLS library and it can be - built to use one out of a fairly large set of libraries - `curl -V` shows -- which one your curl was built to use (if any!). To get a page from an HTTPS -+ which one your curl was built to use (if any). To get a page from an HTTPS - server, simply run curl like: - - curl https://secure.example.com - - ## Certificates - -- In the HTTPS world, you use certificates to validate that you are the one -- you claim to be, as an addition to normal passwords. Curl supports client- -- side certificates. All certificates are locked with a pass phrase, which you -- need to enter before the certificate can be used by curl. The pass phrase -- can be specified on the command line or if not, entered interactively when -- curl queries for it. Use a certificate with curl on an HTTPS server like: -+ In the HTTPS world, you use certificates to validate that you are the one you -+ claim to be, as an addition to normal passwords. Curl supports client- side -+ certificates. All certificates are locked with a passphrase, which you need -+ to enter before the certificate can be used by curl. The passphrase can be -+ specified on the command line or if not, entered interactively when curl -+ queries for it. Use a certificate with curl on an HTTPS server like: - - curl --cert mycert.pem https://secure.example.com - -diff --git a/docs/URL-SYNTAX.md b/docs/URL-SYNTAX.md -index 67f9bdbc6..61682f425 100644 ---- a/docs/URL-SYNTAX.md -+++ b/docs/URL-SYNTAX.md -@@ -1,3 +1,9 @@ -+ -+ - # URL syntax and their use in curl - - ## Specifications -@@ -26,7 +32,7 @@ unlikely that multiple parsers treat URLs the same way. - - Due to the inherent differences between URL parser implementations, it is - considered a security risk to mix different implementations and assume the --same behavior! -+same behavior. - - For example, if you use one parser to check if a URL uses a good hostname or - the correct auth field, and then pass on that same URL to a *second* parser, -@@ -61,7 +67,7 @@ and curl using scripts remain working. - curl's URL parser allows a few deviations from the spec in order to - inter-operate better with URLs that appear in the wild. - --### spaces -+### Spaces - - A URL provided to curl cannot contain spaces. They need to be provided URL - encoded to be accepted in a URL by curl. -@@ -71,12 +77,12 @@ client where a resource has been redirected to, sometimes contain spaces. This - is a violation of RFC 3986 but is fine in the WHATWG spec. curl handles these - by re-encoding them to `%20`. - --### non-ASCII -+### Non-ASCII - - Byte values in a provided URL that are outside of the printable ASCII range - are percent-encoded by curl. - --### multiple slashes -+### Multiple slashes - - An absolute URL always starts with a "scheme" followed by a colon. For all the - schemes curl supports, the colon must be followed by two slashes according to -@@ -102,7 +108,7 @@ Based on what the hostname starts with, curl "guesses" what protocol to use: - - `pop3.` means POP3 - - all other means HTTP - --### globbing letters -+### Globbing letters - - The curl command line tool supports "globbing" of URLs. It means that you can - create ranges and lists using `[N-M]` and `{one,two,three}` sequences. The -@@ -191,7 +197,7 @@ Transitional Processing. The two standards have a huge overlap but differ - slightly, perhaps most famously in how they deal with the German "double s" - (`ß`). - --When winidn is used, curl uses IDNA 2003 Transitional Processing, like the rest -+When WinIDN is used, curl uses IDNA 2003 Transitional Processing, like the rest - of Windows. - - ## Port number -@@ -220,7 +226,7 @@ directory listing for the root / home directory is returned. - FTP servers typically put the user in its "home directory" after login, which - then differs between users. To explicitly specify the root directory of an FTP - server, start the path with double slash `//` or `/%2f` (2F is the hexadecimal --value of the ascii code for the slash). -+value of the ASCII code for the slash). - - ## FILE - -diff --git a/docs/VERSIONS.md b/docs/VERSIONS.md -index fc21749ee..a3159aa6c 100644 ---- a/docs/VERSIONS.md -+++ b/docs/VERSIONS.md -@@ -1,3 +1,9 @@ -+ -+ - Version Numbers and Releases - ============================ - -diff --git a/docs/VULN-DISCLOSURE-POLICY.md b/docs/VULN-DISCLOSURE-POLICY.md -index f18db6d52..fa379cf53 100644 ---- a/docs/VULN-DISCLOSURE-POLICY.md -+++ b/docs/VULN-DISCLOSURE-POLICY.md -@@ -1,3 +1,9 @@ -+ -+ - # curl vulnerability disclosure policy - - This document describes how security vulnerabilities are handled in the curl -@@ -256,7 +262,7 @@ data. We consider this functionality a best-effort and omissions are not - security vulnerabilities. - - - not all systems allow the arguments to be blanked in the first place -- - since curl blanks the argument itself they area readable for a short moment -+ - since curl blanks the argument itself they are readable for a short moment - no matter what - - virtually every argument can contain sensitive data, depending on use - - blanking all arguments would make it impractical for users to differentiate -@@ -292,3 +298,18 @@ is curl working as designed and is not a curl security problem. Escape - sequences, moving cursor, changing color etc, is also frequently used for - good. To reduce the risk of getting fooled, save files and browse them after - download using a display method that minimizes risks. -+ -+## NULL dereferences and crashes -+ -+If a malicious server can trigger a NULL dereference in curl or otherwise -+cause curl to crash (and nothing worse), chances are big that we do not -+consider that a security problem. -+ -+Malicious servers can already cause considerable harm and denial of service -+like scenarios without having to trigger such code paths. For example by -+stalling, being terribly slow or by delivering enormous amounts of data. -+Additionally, applications are expected to handle "normal" crashes without -+that being the end of the world. -+ -+There need to be more and special circumstances to treat such problems as -+security issues. -diff --git a/docs/cmdline-opts/CMakeLists.txt b/docs/cmdline-opts/CMakeLists.txt -index 99ec66c31..f6a947567 100644 ---- a/docs/cmdline-opts/CMakeLists.txt -+++ b/docs/cmdline-opts/CMakeLists.txt -@@ -21,19 +21,22 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --set(MANPAGE "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.1") --set(ASCIIPAGE "${CURL_BINARY_DIR}/docs/cmdline-opts/curl.txt") -- --# Load DPAGES and OTHERPAGES from shared file -+# Get 'DPAGES' variable - transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - --add_custom_command(OUTPUT "${MANPAGE}" -- COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && "${PERL_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/scripts/managen mainpage ${DPAGES} > "${MANPAGE}" -- COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && "${PERL_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/scripts/managen ascii ${DPAGES} > "${ASCIIPAGE}" -+add_custom_command(OUTPUT "${CURL_MANPAGE}" "${CURL_ASCIIPAGE}" -+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -+ COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/managen" mainpage ${DPAGES} > "${CURL_MANPAGE}" -+ COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/managen" ascii ${DPAGES} > "${CURL_ASCIIPAGE}" -+ DEPENDS -+ "${PROJECT_SOURCE_DIR}/scripts/managen" -+ ${DPAGES} - VERBATIM - ) --add_custom_target(generate-curl.1 ALL DEPENDS "${MANPAGE}") -+ -+add_custom_target(generate-curl.1 ALL DEPENDS "${CURL_MANPAGE}") -+ - if(NOT CURL_DISABLE_INSTALL) -- install(FILES "${MANPAGE}" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) -+ install(FILES "${CURL_MANPAGE}" DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") - endif() -diff --git a/docs/cmdline-opts/MANPAGE.md b/docs/cmdline-opts/MANPAGE.md -index 1f9749bc5..3e2e7151f 100644 ---- a/docs/cmdline-opts/MANPAGE.md -+++ b/docs/cmdline-opts/MANPAGE.md -@@ -45,7 +45,7 @@ A line that starts with ``. - Help: (short text for the --help output for this option) - Long: (long form name, without dashes) - Magic: (description of "magic" options) -- Multi: single/append/boolean/mutex/custom (if used more than once) -+ Multi: single/append/boolean/mutex/custom/per-URL (if used more than once) - Mutexed: (space separated list of options this overrides, no dashes) - Protocols: (space separated list for which protocols this option works) - Requires: (space separated list of features this requires, no dashes) -diff --git a/docs/cmdline-opts/Makefile.am b/docs/cmdline-opts/Makefile.am -index 81a4afe1b..b087e3852 100644 ---- a/docs/cmdline-opts/Makefile.am -+++ b/docs/cmdline-opts/Makefile.am -@@ -27,8 +27,6 @@ AUTOMAKE_OPTIONS = foreign no-dependencies - MANPAGE = curl.1 - ASCIIPAGE = curl.txt - --man_MANS = $(MANPAGE) -- - include Makefile.inc - - EXTRA_DIST = $(DPAGES) MANPAGE.md $(SUPPORT) CMakeLists.txt mainpage.idx -@@ -38,23 +36,28 @@ GN_0 = @echo " GENERATE" $@; - GN_1 = - GN_ = $(GN_0) - --MANAGEN=$(abs_top_srcdir)/scripts/managen -+MANAGEN=$(top_srcdir)/scripts/managen -+MAXLINE=$(top_srcdir)/scripts/maxline -+ -+# Maximum number of columns accepted in the ASCII version of the manpage -+INCDIR=$(top_srcdir)/include - - if BUILD_DOCS - CLEANFILES = $(MANPAGE) $(ASCIIPAGE) -+man_MANS = $(MANPAGE) - - all: $(MANPAGE) $(ASCIIPAGE) - - endif - - $(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN) -- $(GEN)(rm -f $(MANPAGE) && (cd $(srcdir) && @PERL@ $(MANAGEN) mainpage $(DPAGES)) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE)) -+ $(GEN)(rm -f $(MANPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) mainpage $(DPAGES) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE)) - - $(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN) -- $(GEN)(rm -f $(ASCIIPAGE) && (cd $(srcdir) && @PERL@ $(MANAGEN) ascii $(DPAGES)) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE)) -+ $(GEN)(rm -f $(ASCIIPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) ascii $(DPAGES) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE)) - - listhelp: -- $(MANAGEN) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c -+ $(MANAGEN) -d $(srcdir) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c - - listcats: - @$(MANAGEN) listcats $(DPAGES) -diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc -index 428cc3bab..3bcffa49f 100644 ---- a/docs/cmdline-opts/Makefile.inc -+++ b/docs/cmdline-opts/Makefile.inc -@@ -89,7 +89,9 @@ DPAGES = \ - doh-cert-status.md \ - doh-insecure.md \ - doh-url.md \ -+ dump-ca-embed.md \ - dump-header.md \ -+ ech.md \ - egd-file.md \ - engine.md \ - etag-compare.md \ -@@ -132,14 +134,15 @@ DPAGES = \ - http3.md \ - http3-only.md \ - ignore-content-length.md \ -- include.md \ - insecure.md \ - interface.md \ -+ ip-tos.md \ - ipfs-gateway.md \ - ipv4.md \ - ipv6.md \ - json.md \ - junk-session-cookies.md \ -+ keepalive-cnt.md \ - keepalive-time.md \ - key-type.md \ - key.md \ -@@ -160,6 +163,7 @@ DPAGES = \ - max-redirs.md \ - max-time.md \ - metalink.md \ -+ mptcp.md \ - negotiate.md \ - netrc-file.md \ - netrc-optional.md \ -@@ -247,7 +251,9 @@ DPAGES = \ - sasl-ir.md \ - service-name.md \ - show-error.md \ -+ show-headers.md \ - silent.md \ -+ skip-existing.md \ - socks4.md \ - socks4a.md \ - socks5-basic.md \ -@@ -275,6 +281,7 @@ DPAGES = \ - tftp-blksize.md \ - tftp-no-options.md \ - time-cond.md \ -+ tls-earlydata.md \ - tls-max.md \ - tls13-ciphers.md \ - tlsauthtype.md \ -@@ -301,5 +308,6 @@ DPAGES = \ - variable.md \ - verbose.md \ - version.md \ -+ vlan-priority.md \ - write-out.md \ - xattr.md -diff --git a/docs/cmdline-opts/_ENVIRONMENT.md b/docs/cmdline-opts/_ENVIRONMENT.md -index af60ac8d0..02561193b 100644 ---- a/docs/cmdline-opts/_ENVIRONMENT.md -+++ b/docs/cmdline-opts/_ENVIRONMENT.md -@@ -87,7 +87,7 @@ names named after the destination connection id (in hex). Do note that these - files can become rather large. Works with the ngtcp2 and quiche QUIC backends. - - ## `SHELL` --Used on VMS when trying to detect if using a **DCL** or a **unix** shell. -+Used on VMS when trying to detect if using a **DCL** or a **Unix** shell. - - ## `SSL_CERT_DIR` - If set, it is used as the --capath value. This environment variable is ignored -@@ -101,8 +101,8 @@ if Schannel is used as the TLS backend. - If you set this environment variable to a filename, curl stores TLS secrets - from its connections in that file when invoked to enable you to analyze the - TLS traffic in real time using network analyzing tools such as Wireshark. This --works with the following TLS backends: OpenSSL, libressl, BoringSSL, GnuTLS --and wolfSSL. -+works with the following TLS backends: OpenSSL, LibreSSL (TLS 1.2 max), -+BoringSSL, GnuTLS and wolfSSL. - - ## `USERPROFILE` - On Windows, this variable is used when trying to find the home directory. If -diff --git a/docs/cmdline-opts/_EXITCODES.md b/docs/cmdline-opts/_EXITCODES.md -index c5a928b59..a16f47527 100644 ---- a/docs/cmdline-opts/_EXITCODES.md -+++ b/docs/cmdline-opts/_EXITCODES.md -@@ -105,7 +105,7 @@ Too many redirects. When following redirects, curl hit the maximum amount. - ## 48 - Unknown option specified to libcurl. This indicates that you passed a weird - option to curl that was passed on to libcurl and rejected. Read up in the --manual! -+manual. - ## 49 - Malformed telnet option. - ## 52 -diff --git a/docs/cmdline-opts/_OPTIONS.md b/docs/cmdline-opts/_OPTIONS.md -index 106298e74..b6b75b3f3 100644 ---- a/docs/cmdline-opts/_OPTIONS.md -+++ b/docs/cmdline-opts/_OPTIONS.md -@@ -1,6 +1,7 @@ - - - # OPTIONS -+ - Options start with one or two dashes. Many of the options require an - additional value next to them. If provided text does not start with a dash, it - is presumed to be and treated as a URL. -@@ -24,3 +25,5 @@ clean option state, except for the options that are global. Global options - retain their values and meaning even after --next. - - The following options are global: `%GLOBALS`. -+ -+# ALL OPTIONS -diff --git a/docs/cmdline-opts/_PROTOCOLS.md b/docs/cmdline-opts/_PROTOCOLS.md -index 0d4c2374e..af7019ab0 100644 ---- a/docs/cmdline-opts/_PROTOCOLS.md -+++ b/docs/cmdline-opts/_PROTOCOLS.md -@@ -49,3 +49,5 @@ Fetching a telnet URL starts an interactive session where it sends what it - reads on stdin and outputs what the server sends it. - ## TFTP - curl can do TFTP downloads and uploads. -+## WS(S) -+WebSocket done over HTTP/1. WSS implies that it works over HTTPS. -diff --git a/docs/cmdline-opts/_VARIABLES.md b/docs/cmdline-opts/_VARIABLES.md -index aa6a8ae4f..e46b67553 100644 ---- a/docs/cmdline-opts/_VARIABLES.md -+++ b/docs/cmdline-opts/_VARIABLES.md -@@ -11,12 +11,12 @@ variable `name` inserted, or a blank if the name does not exist as a - variable. Insert `{{` verbatim in the string by prefixing it with a backslash, - like `\{{`. - --You an access and expand environment variables by first importing them. You --can select to either require the environment variable to be set or you can --provide a default value in case it is not already set. Plain --variable %name --imports the variable called 'name' but exits with an error if that environment -+You access and expand environment variables by first importing them. You -+select to either require the environment variable to be set or you can provide -+a default value in case it is not already set. Plain `--variable %name` -+imports the variable called `name` but exits with an error if that environment - variable is not already set. To provide a default value if it is not set, use ----variable %name=content or --variable %name@content. -+`--variable %name=content` or `--variable %name@content`. - - Example. Get the USER environment variable into the URL, fail if USER is not - set: -diff --git a/docs/cmdline-opts/ca-native.md b/docs/cmdline-opts/ca-native.md -index a771a7a81..3d773a8c4 100644 ---- a/docs/cmdline-opts/ca-native.md -+++ b/docs/cmdline-opts/ca-native.md -@@ -10,6 +10,7 @@ Multi: boolean - See-also: - - cacert - - capath -+ - dump-ca-embed - - insecure - Example: - - --ca-native $URL -diff --git a/docs/cmdline-opts/cacert.md b/docs/cmdline-opts/cacert.md -index 3268f966d..00c277e2e 100644 ---- a/docs/cmdline-opts/cacert.md -+++ b/docs/cmdline-opts/cacert.md -@@ -10,6 +10,7 @@ Added: 7.5 - Multi: single - See-also: - - capath -+ - dump-ca-embed - - insecure - Example: - - --cacert CA-file.txt $URL -@@ -26,10 +27,13 @@ curl recognizes the environment variable named 'CURL_CA_BUNDLE' if it is set - and the TLS backend is not Schannel, and uses the given path as a path to a CA - cert bundle. This option overrides that variable. - --The windows version of curl automatically looks for a CA certs file named -+(Windows) curl automatically looks for a CA certs file named - 'curl-ca-bundle.crt', either in the same directory as curl.exe, or in the - Current Working Directory, or in any folder along your PATH. - -+curl 8.11.0 added a build-time option to disable this search behavior, and -+another option to restrict search to the application's directory. -+ - (iOS and macOS only) If curl is built against Secure Transport, then this - option is supported for backward compatibility with other SSL engines, but it - should not be set. If the option is not set, then curl uses the certificates -diff --git a/docs/cmdline-opts/capath.md b/docs/cmdline-opts/capath.md -index 58919dd4a..51be39e29 100644 ---- a/docs/cmdline-opts/capath.md -+++ b/docs/cmdline-opts/capath.md -@@ -10,6 +10,7 @@ Added: 7.9.8 - Multi: single - See-also: - - cacert -+ - dump-ca-embed - - insecure - Example: - - --capath /local/directory $URL -diff --git a/docs/cmdline-opts/cert.md b/docs/cmdline-opts/cert.md -index 715fcb831..d5d19a39d 100644 ---- a/docs/cmdline-opts/cert.md -+++ b/docs/cmdline-opts/cert.md -@@ -39,6 +39,10 @@ PKCS#11 URI. If a PKCS#11 URI is provided, then the --engine option is set as - `pkcs11` if none was provided and the --cert-type option is set as `ENG` if - none was provided. - -+If curl is built against GnuTLS library, a PKCS#11 URI can be used to specify -+a certificate located in a PKCS#11 device. A string beginning with `pkcs11:` -+is interpreted as a PKCS#11 URI. -+ - (iOS and macOS only) If curl is built against Secure Transport, then the - certificate string can either be the name of a certificate/private key in the - system or user keychain, or the path to a PKCS#12-encoded certificate and -diff --git a/docs/cmdline-opts/ciphers.md b/docs/cmdline-opts/ciphers.md -index 9d7e0c6fe..6a597a2c8 100644 ---- a/docs/cmdline-opts/ciphers.md -+++ b/docs/cmdline-opts/ciphers.md -@@ -2,23 +2,24 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: ciphers --Arg: --Help: SSL ciphers to use -+Arg: -+Help: TLS 1.2 (1.1, 1.0) ciphers to use - Protocols: TLS - Category: tls - Added: 7.9 - Multi: single - See-also: -- - tlsv1.3 - - tls13-ciphers - - proxy-ciphers -+ - curves - Example: -- - --ciphers ECDHE-ECDSA-AES256-CCM8 $URL -+ - --ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 $URL - --- - - # `--ciphers` - --Specifies which ciphers to use in the connection. The list of ciphers must --specify valid ciphers. Read up on SSL cipher list details on this URL: -+Specifies which cipher suites to use in the connection if it negotiates -+TLS 1.2 (1.1, 1.0). The list of ciphers suites must specify valid ciphers. -+Read up on cipher suite details on this URL: - - https://curl.se/docs/ssl-ciphers.html -diff --git a/docs/cmdline-opts/connect-timeout.md b/docs/cmdline-opts/connect-timeout.md -index e1400811e..dc5f92704 100644 ---- a/docs/cmdline-opts/connect-timeout.md -+++ b/docs/cmdline-opts/connect-timeout.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: connect-timeout - Arg: - Help: Maximum time allowed to connect --Category: connection -+Category: connection timeout - Added: 7.7 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/connect-to.md b/docs/cmdline-opts/connect-to.md -index 360ef0da2..578256165 100644 ---- a/docs/cmdline-opts/connect-to.md -+++ b/docs/cmdline-opts/connect-to.md -@@ -3,9 +3,9 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: connect-to - Arg: --Help: Connect to host -+Help: Connect to host2 instead of host1 - Added: 7.49.0 --Category: connection -+Category: connection dns - Multi: append - See-also: - - resolve -@@ -28,3 +28,13 @@ original hostname and port number. - A hostname specified to this option is compared as a string, so it needs to - match the name used in request URL. It can be either numerical such as - `127.0.0.1` or the full host name such as `example.org`. -+ -+Example: redirect connects from the example.com hostname to 127.0.0.1 -+independently of port number: -+ -+ curl --connect-to example.com::127.0.0.1: https://example.com/ -+ -+Example: redirect connects from all hostnames to 127.0.0.1 independently of -+port number: -+ -+ curl --connect-to ::127.0.0.1: http://example.com/ -diff --git a/docs/cmdline-opts/cookie-jar.md b/docs/cmdline-opts/cookie-jar.md -index f99368591..49a9440bf 100644 ---- a/docs/cmdline-opts/cookie-jar.md -+++ b/docs/cmdline-opts/cookie-jar.md -@@ -11,6 +11,7 @@ Added: 7.9 - Multi: single - See-also: - - cookie -+ - junk-session-cookies - Example: - - -c store-here.txt $URL - - -c store-here.txt -b read-these $URL -diff --git a/docs/cmdline-opts/cookie.md b/docs/cmdline-opts/cookie.md -index cbc8b8457..50f977e70 100644 ---- a/docs/cmdline-opts/cookie.md -+++ b/docs/cmdline-opts/cookie.md -@@ -21,20 +21,21 @@ Example: - - # `--cookie` - --Pass the data to the HTTP server in the Cookie header. It is supposedly the --data previously received from the server in a `Set-Cookie:` line. The data --should be in the format `NAME1=VALUE1; NAME2=VALUE2` or as a single filename. -- --When given a set of specific cookies and not a filename, it makes curl use the --cookie header with this content explicitly in all outgoing request(s). If --multiple requests are done due to authentication, followed redirects or --similar, they all get this cookie header passed on. -- --If no `=` symbol is used in the argument, it is instead treated as a filename --to read previously stored cookie from. This option also activates the cookie --engine which makes curl record incoming cookies, which may be handy if you are --using this in combination with the --location option or do multiple URL --transfers on the same invoke. -+This option has two slightly separate cookie sending functions. -+ -+Either: pass the exact data to send to the HTTP server in the Cookie header. -+It is supposedly data previously received from the server in a `Set-Cookie:` -+line. The data should be in the format `NAME1=VALUE1; NAME2=VALUE2`. When -+given a set of specific cookies, curl populates its cookie header with this -+content explicitly in all outgoing request(s). If multiple requests are done -+due to authentication, followed redirects or similar, they all get this cookie -+header passed on. -+ -+Or: If no `=` symbol is used in the argument, it is instead treated as a -+filename to read previously stored cookie from. This option also activates the -+cookie engine which makes curl record incoming cookies, which may be handy if -+you are using this in combination with the --location option or do multiple -+URL transfers on the same invoke. - - If the filename is a single minus ("-"), curl reads the contents from stdin. - If the filename is an empty string ("") and is the only cookie input, curl -diff --git a/docs/cmdline-opts/create-dirs.md b/docs/cmdline-opts/create-dirs.md -index fcbeb3343..89d24f76b 100644 ---- a/docs/cmdline-opts/create-dirs.md -+++ b/docs/cmdline-opts/create-dirs.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: create-dirs - Help: Create necessary local directory hierarchy --Category: curl -+Category: output - Added: 7.10.3 - Multi: boolean - See-also: -@@ -21,6 +21,6 @@ mentioned with the --output option combined with the path possibly set with - --output-dir. If the combined output filename uses no directory, or if the - directories it mentions already exist, no directories are created. - --Created directories are made with mode 0750 on unix style file systems. -+Created directories are made with mode 0750 on Unix-style file systems. - - To create remote directories when using FTP or SFTP, try --ftp-create-dirs. -diff --git a/docs/cmdline-opts/crlf.md b/docs/cmdline-opts/crlf.md -index 81a14ef6f..c36884113 100644 ---- a/docs/cmdline-opts/crlf.md -+++ b/docs/cmdline-opts/crlf.md -@@ -17,5 +17,3 @@ Example: - - Convert line feeds to carriage return plus line feeds in upload. Useful for - **MVS (OS/390)**. -- --(SMTP added in 7.40.0) -diff --git a/docs/cmdline-opts/data-binary.md b/docs/cmdline-opts/data-binary.md -index 1ce53b32c..4c5e4da8d 100644 ---- a/docs/cmdline-opts/data-binary.md -+++ b/docs/cmdline-opts/data-binary.md -@@ -18,9 +18,10 @@ Example: - - Post data exactly as specified with no extra processing whatsoever. - --If you start the data with the letter @, the rest should be a filename. Data --is posted in a similar manner as --data does, except that newlines and --carriage returns are preserved and conversions are never done. -+If you start the data with the letter @, the rest should be a filename. -+`@-` makes curl read the data from stdin. Data is posted in a similar -+manner as --data does, except that newlines and carriage returns are -+preserved and conversions are never done. - - Like --data the default content-type sent to the server is - application/x-www-form-urlencoded. If you want the data to be treated as -diff --git a/docs/cmdline-opts/data-urlencode.md b/docs/cmdline-opts/data-urlencode.md -index 2bd84f3f1..b4680e61a 100644 ---- a/docs/cmdline-opts/data-urlencode.md -+++ b/docs/cmdline-opts/data-urlencode.md -@@ -30,7 +30,7 @@ curl using one of the following syntaxes: - ## content - URL-encode the content and pass that on. Just be careful so that the content - does not contain any `=` or `@` symbols, as that makes the syntax match one of --the other cases below! -+the other cases below. - - ## =content - URL-encode the content and pass that on. The preceding `=` symbol is not -@@ -42,7 +42,7 @@ expected to be URL-encoded already. - - ## @filename - load data from the given file (including any newlines), URL-encode that data --and pass it on in the POST. -+and pass it on in the POST. Using `@-` makes curl read the data from stdin. - - ## name@filename - load data from the given file (including any newlines), URL-encode that data -diff --git a/docs/cmdline-opts/disable.md b/docs/cmdline-opts/disable.md -index e22a2bb4a..1370b91d7 100644 ---- a/docs/cmdline-opts/disable.md -+++ b/docs/cmdline-opts/disable.md -@@ -18,6 +18,3 @@ Example: - If used as the **first** parameter on the command line, the *curlrc* config - file is not read or used. See the --config for details on the default config - file search path. -- --Prior to 7.50.0 curl supported the short option name *q* but not the long --option name *disable*. -diff --git a/docs/cmdline-opts/doh-insecure.md b/docs/cmdline-opts/doh-insecure.md -index 684428ddf..72f3cb772 100644 ---- a/docs/cmdline-opts/doh-insecure.md -+++ b/docs/cmdline-opts/doh-insecure.md -@@ -8,10 +8,20 @@ Category: dns tls - Multi: boolean - See-also: - - doh-url -+ - insecure -+ - proxy-insecure - Example: - - --doh-insecure --doh-url https://doh.example $URL - --- - - # `--doh-insecure` - --Same as --insecure but used for DoH (DNS-over-HTTPS). -+By default, every connection curl makes to a DoH server is verified to be -+secure before the transfer takes place. This option tells curl to skip the -+verification step and proceed without checking. -+ -+**WARNING**: using this option makes the DoH transfer and name resolution -+insecure. -+ -+This option is equivalent to --insecure and --proxy-insecure but used for DoH -+(DNS-over-HTTPS) only. -diff --git a/docs/cmdline-opts/doh-url.md b/docs/cmdline-opts/doh-url.md -index 23754cac1..0f745af3b 100644 ---- a/docs/cmdline-opts/doh-url.md -+++ b/docs/cmdline-opts/doh-url.md -@@ -11,6 +11,7 @@ See-also: - - doh-insecure - Example: - - --doh-url https://doh.example $URL -+ - --doh-url https://doh.example --resolve doh.example:443:192.0.2.1 $URL - --- - - # `--doh-url` -@@ -23,5 +24,7 @@ name lookups take place over SSL. However, the certificate verification - settings are not inherited but are controlled separately via --doh-insecure - and --doh-cert-status. - -+By default, DoH is bypassed when initially looking up DNS records of the DoH server. You can specify the IP address(es) of the DoH server with --resolve to avoid this. -+ - This option is unset if an empty string "" is used as the URL. - (Added in 7.85.0) -diff --git a/docs/cmdline-opts/dump-ca-embed.md b/docs/cmdline-opts/dump-ca-embed.md -new file mode 100644 -index 000000000..2ad123014 ---- /dev/null -+++ b/docs/cmdline-opts/dump-ca-embed.md -@@ -0,0 +1,25 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: dump-ca-embed -+Help: Write the embedded CA bundle to standard output -+Protocols: TLS -+Category: http proxy tls -+Added: 8.10.0 -+Multi: boolean -+See-also: -+ - ca-native -+ - cacert -+ - capath -+ - proxy-ca-native -+ - proxy-cacert -+ - proxy-capath -+Example: -+ - --dump-ca-embed -+--- -+ -+# `--dump-ca-embed` -+ -+Write the CA bundle embedded in curl to standard output, then quit. -+ -+If curl was not built with a default CA bundle embedded, the output is empty. -diff --git a/docs/cmdline-opts/dump-header.md b/docs/cmdline-opts/dump-header.md -index 42d3e85ed..bdb0e874e 100644 ---- a/docs/cmdline-opts/dump-header.md -+++ b/docs/cmdline-opts/dump-header.md -@@ -13,15 +13,23 @@ See-also: - - output - Example: - - --dump-header store.txt $URL -+ - --dump-header - $URL -o save - --- - - # `--dump-header` - - Write the received protocol headers to the specified file. If no headers are --received, the use of this option creates an empty file. -+received, the use of this option creates an empty file. Specify `-` as -+filename (a single minus) to have it written to stdout. -+ -+Starting in curl 8.10.0, specify `%` (a single percent sign) as filename -+writes the output to stderr. - - When used in FTP, the FTP server response lines are considered being "headers" - and thus are saved there. - -+Starting in curl 8.11.0, using the --create-dirs option can also create -+missing directory components for the path provided in --dump-header. -+ - Having multiple transfers in one set of operations (i.e. the URLs in one - --next clause), appends them to the same file, separated by a blank line. -diff --git a/docs/cmdline-opts/ech.md b/docs/cmdline-opts/ech.md -new file mode 100644 -index 000000000..61faca677 ---- /dev/null -+++ b/docs/cmdline-opts/ech.md -@@ -0,0 +1,54 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: ech -+Arg: -+Help: Configure ECH -+Added: 8.8.0 -+Category: tls -+Protocols: HTTPS -+Multi: single -+See-also: -+ - doh-url -+Example: -+ - --ech true $URL -+--- -+ -+# `--ech` -+ -+Specifies how to do ECH (Encrypted Client Hello). -+ -+The values allowed for \ can be: -+ -+## "false" (default) -+ -+Do not attempt ECH -+ -+## "grease" -+ -+Send a GREASE ECH extension -+ -+## "true" -+ -+Attempt ECH if possible, but do not fail if ECH is not attempted. -+(The connection fails if ECH is attempted but fails.) -+ -+## "hard" -+ -+Attempt ECH and fail if that is not possible. -+ECH only works with TLS 1.3 and also requires using -+DoH or providing an ECHConfigList on the command line. -+ -+## "ecl:" -+ -+A base64 encoded ECHConfigList that is used for ECH. -+ -+## "pn:" -+ -+A name to use to over-ride the `public_name` field of an ECHConfigList -+(only available with OpenSSL TLS support) -+ -+## Errors -+ -+Most errors cause error -+*CURLE_ECH_REQUIRED* (101). -diff --git a/docs/cmdline-opts/egd-file.md b/docs/cmdline-opts/egd-file.md -index b68b7d496..ef16b9964 100644 ---- a/docs/cmdline-opts/egd-file.md -+++ b/docs/cmdline-opts/egd-file.md -@@ -5,7 +5,7 @@ Long: egd-file - Arg: - Help: EGD socket path for random data - Protocols: TLS --Category: tls -+Category: deprecated - Added: 7.7 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/expect100-timeout.md b/docs/cmdline-opts/expect100-timeout.md -index ce69227ad..80cf4eba6 100644 ---- a/docs/cmdline-opts/expect100-timeout.md -+++ b/docs/cmdline-opts/expect100-timeout.md -@@ -6,7 +6,7 @@ Arg: - Help: How long to wait for 100-continue - Protocols: HTTP - Added: 7.47.0 --Category: http -+Category: http timeout - Multi: single - See-also: - - connect-timeout -@@ -21,5 +21,5 @@ response when curl emits an Expects: 100-continue header in its request. By - default curl waits one second. This option accepts decimal values. When curl - stops waiting, it continues as if a response was received. - --The decimal value needs to provided using a dot (`.`) as decimal separator - -+The decimal value needs to be provided using a dot (`.`) as decimal separator - - not the local version even if it might be using another separator. -diff --git a/docs/cmdline-opts/fail-early.md b/docs/cmdline-opts/fail-early.md -index bb22e1470..67edbf919 100644 ---- a/docs/cmdline-opts/fail-early.md -+++ b/docs/cmdline-opts/fail-early.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: fail-early - Help: Fail on first transfer error - Added: 7.52.0 --Category: curl -+Category: curl global - Multi: boolean - Scope: global - See-also: -diff --git a/docs/cmdline-opts/fail.md b/docs/cmdline-opts/fail.md -index 8591e330d..0c8db1367 100644 ---- a/docs/cmdline-opts/fail.md -+++ b/docs/cmdline-opts/fail.md -@@ -18,11 +18,17 @@ Example: - - # `--fail` - --Fail fast with no output at all on server errors. This is useful to enable --scripts and users to better deal with failed attempts. In normal cases when an --HTTP server fails to deliver a document, it returns an HTML document stating --so (which often also describes why and more). This command line option --prevents curl from outputting that and return error 22. -+Fail with error code 22 and with no response body output at all for HTTP -+transfers returning HTTP response codes at 400 or greater. -+ -+In normal cases when an HTTP server fails to deliver a document, it returns a -+body of text stating so (which often also describes why and more) and a 4xx -+HTTP response code. This command line option prevents curl from outputting -+that data and instead returns error 22 early. By default, curl does not -+consider HTTP response codes to indicate failure. -+ -+To get both the error code and also save the content, use --fail-with-body -+instead. - - This method is not fail-safe and there are occasions where non-successful - response codes slip through, especially when authentication is involved -diff --git a/docs/cmdline-opts/false-start.md b/docs/cmdline-opts/false-start.md -index f25af2374..c6c44ad54 100644 ---- a/docs/cmdline-opts/false-start.md -+++ b/docs/cmdline-opts/false-start.md -@@ -20,4 +20,4 @@ client starts sending application data before verifying the server's Finished - message, thus saving a round trip when performing a full handshake. - - This functionality is currently only implemented in the Secure Transport (on --iOS 7.0 or later, or OS X 10.9 or later) backend. -+iOS 7.0 or later, or macOS 10.9 or later) backend. -diff --git a/docs/cmdline-opts/form-escape.md b/docs/cmdline-opts/form-escape.md -index 083c29e16..0f93fde7e 100644 ---- a/docs/cmdline-opts/form-escape.md -+++ b/docs/cmdline-opts/form-escape.md -@@ -3,9 +3,9 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: form-escape - Help: Escape form fields using backslash --Protocols: HTTP -+Protocols: HTTP imap smtp - Added: 7.81.0 --Category: http upload -+Category: http upload post - Multi: single - See-also: - - form -diff --git a/docs/cmdline-opts/form-string.md b/docs/cmdline-opts/form-string.md -index 3c1f7b532..e58ad625d 100644 ---- a/docs/cmdline-opts/form-string.md -+++ b/docs/cmdline-opts/form-string.md -@@ -5,7 +5,7 @@ Long: form-string - Help: Specify multipart MIME data - Protocols: HTTP SMTP IMAP - Arg: --Category: http upload -+Category: http upload post smtp imap - Added: 7.13.2 - Multi: append - See-also: -diff --git a/docs/cmdline-opts/form.md b/docs/cmdline-opts/form.md -index 8a4c91e5a..17bfcac0e 100644 ---- a/docs/cmdline-opts/form.md -+++ b/docs/cmdline-opts/form.md -@@ -7,7 +7,7 @@ Arg: - Help: Specify multipart MIME data - Protocols: HTTP SMTP IMAP - Mutexed: data head upload-file --Category: http upload -+Category: http upload post imap smtp - Added: 5.0 - Multi: append - See-also: -@@ -72,11 +72,13 @@ filename=, like this: - - If filename/path contains ',' or ';', it must be quoted by double-quotes like: - -- curl -F "file=@\"local,file\";filename=\"name;in;post\"" example.com -+ curl -F "file=@\"local,file\";filename=\"name;in;post\"" \ -+ https://example.com - - or - -- curl -F 'file=@"local,file";filename="name;in;post"' example.com -+ curl -F 'file=@"local,file";filename="name;in;post"' \ -+ https://example.com - - Note that if a filename/path is quoted by double-quotes, any double-quote - or backslash within the filename must be escaped by backslash. -@@ -84,7 +86,8 @@ or backslash within the filename must be escaped by backslash. - Quoting must also be applied to non-file data if it contains semicolons, - leading/trailing spaces or leading double quotes: - -- curl -F 'colors="red; green; blue";type=text/x-myapp' example.com -+ curl -F 'colors="red; green; blue";type=text/x-myapp' \ -+ https://example.com - - You can add custom headers to the field by setting headers=, like - -diff --git a/docs/cmdline-opts/ftp-create-dirs.md b/docs/cmdline-opts/ftp-create-dirs.md -index 5151e336c..3e851ccae 100644 ---- a/docs/cmdline-opts/ftp-create-dirs.md -+++ b/docs/cmdline-opts/ftp-create-dirs.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: ftp-create-dirs - Protocols: FTP SFTP - Help: Create the remote dirs if not present --Category: ftp sftp curl -+Category: ftp sftp - Added: 7.10.7 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/get.md b/docs/cmdline-opts/get.md -index f8c8cf2f9..ac0560ab6 100644 ---- a/docs/cmdline-opts/get.md -+++ b/docs/cmdline-opts/get.md -@@ -5,7 +5,7 @@ Long: get - Short: G - Help: Put the post data in the URL and use GET - Protocols: HTTP --Category: http upload -+Category: http - Added: 7.8.1 - Multi: boolean - See-also: -@@ -19,10 +19,10 @@ Example: - - # `--get` - --When used, this option makes all data specified with --data, --data-binary --or --data-urlencode to be used in an HTTP GET request instead of the POST --request that otherwise would be used. The data is appended to the URL --with a '?' separator. -+When used, this option makes all data specified with --data, --data-binary or -+--data-urlencode to be used in an HTTP GET request instead of the POST request -+that otherwise would be used. curl appends the provided data to the URL as a -+query string. - - If used in combination with --head, the POST data is instead appended to the - URL with a HEAD request. -diff --git a/docs/cmdline-opts/happy-eyeballs-timeout-ms.md b/docs/cmdline-opts/happy-eyeballs-timeout-ms.md -index 8370ee92b..f4b492db0 100644 ---- a/docs/cmdline-opts/happy-eyeballs-timeout-ms.md -+++ b/docs/cmdline-opts/happy-eyeballs-timeout-ms.md -@@ -5,7 +5,7 @@ Long: happy-eyeballs-timeout-ms - Arg: - Help: Time for IPv6 before IPv4 - Added: 7.59.0 --Category: connection -+Category: connection timeout - Multi: single - See-also: - - max-time -diff --git a/docs/cmdline-opts/head.md b/docs/cmdline-opts/head.md -index be4dbb87f..353ef9a01 100644 ---- a/docs/cmdline-opts/head.md -+++ b/docs/cmdline-opts/head.md -@@ -18,6 +18,6 @@ Example: - - # `--head` - --Fetch the headers only! HTTP-servers feature the command HEAD which this uses --to get nothing but the header of a document. When used on an FTP or FILE file, -+Fetch the headers only. HTTP-servers feature the command HEAD which this uses -+to get nothing but the header of a document. When used on an FTP or FILE URL, - curl displays the file size and last modification time only. -diff --git a/docs/cmdline-opts/header.md b/docs/cmdline-opts/header.md -index 13ca4cb32..17219f383 100644 ---- a/docs/cmdline-opts/header.md -+++ b/docs/cmdline-opts/header.md -@@ -46,14 +46,14 @@ other safe guards. That includes white space and control characters. - - This option can take an argument in @filename style, which then adds a header - for each line in the input file. Using @- makes curl read the header file from --stdin. Added in 7.55.0. -+stdin. (Added in 7.55.0) - - Please note that most anti-spam utilities check the presence and value of - several MIME mail headers: these are `From:`, `To:`, `Date:` and `Subject:` - among others and should be added with this option. - --You need --proxy-header to send custom headers intended for an HTTP --proxy. Added in 7.37.0. -+You need --proxy-header to send custom headers intended for an HTTP proxy. -+(Added in 7.37.0) - - Passing on a "Transfer-Encoding: chunked" header when doing an HTTP request - with a request body, makes curl send the data using chunked encoding. -diff --git a/docs/cmdline-opts/help.md b/docs/cmdline-opts/help.md -index 7477a1e40..122c55cd4 100644 ---- a/docs/cmdline-opts/help.md -+++ b/docs/cmdline-opts/help.md -@@ -2,7 +2,7 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: help --Arg: -+Arg: - Short: h - Help: Get help for commands - Category: important curl -@@ -12,15 +12,28 @@ See-also: - - verbose - Example: - - --help all -+ - --help --insecure -+ - --help -f - --- - - # `--help` - --Usage help. List all curl command line options within the given **category**. -+Usage help. Provide help for the subject given as an optional argument. - - If no argument is provided, curl displays the most important command line - arguments. - --For category **all**, curl displays help for all options. -+The argument can either be a **category** or a **command line option**. When a -+category is provided, curl shows all command line options within the given -+category. Specify category `all` to list all available options. - --If **category** is specified, curl displays all available help categories. -+If `category` is specified, curl displays all available help categories. -+ -+If the provided subject is instead an existing command line option, specified -+either in its short form with a single dash and a single letter, or in the -+long form with two dashes and a longer name, curl displays a help text for -+that option in the terminal. -+ -+The help output is extensive for some options. -+ -+If the provided command line option is not known, curl says so. -diff --git a/docs/cmdline-opts/hostpubmd5.md b/docs/cmdline-opts/hostpubmd5.md -index 7dc873254..5d480a5bc 100644 ---- a/docs/cmdline-opts/hostpubmd5.md -+++ b/docs/cmdline-opts/hostpubmd5.md -@@ -6,7 +6,7 @@ Arg: - Help: Acceptable MD5 hash of host public key - Protocols: SFTP SCP - Added: 7.17.1 --Category: sftp scp -+Category: sftp scp ssh - Multi: single - See-also: - - hostpubsha256 -diff --git a/docs/cmdline-opts/hostpubsha256.md b/docs/cmdline-opts/hostpubsha256.md -index 8ec080551..35aa8ff7d 100644 ---- a/docs/cmdline-opts/hostpubsha256.md -+++ b/docs/cmdline-opts/hostpubsha256.md -@@ -6,7 +6,7 @@ Arg: - Help: Acceptable SHA256 hash of host public key - Protocols: SFTP SCP - Added: 7.80.0 --Category: sftp scp -+Category: sftp scp ssh - Multi: single - See-also: - - hostpubmd5 -diff --git a/docs/cmdline-opts/http2-prior-knowledge.md b/docs/cmdline-opts/http2-prior-knowledge.md -index 727010941..5dffe26a7 100644 ---- a/docs/cmdline-opts/http2-prior-knowledge.md -+++ b/docs/cmdline-opts/http2-prior-knowledge.md -@@ -23,3 +23,7 @@ Issue a non-TLS HTTP requests using HTTP/2 directly without HTTP/1.1 Upgrade. - It requires prior knowledge that the server supports HTTP/2 straight away. - HTTPS requests still do HTTP/2 the standard way with negotiated protocol - version in the TLS handshake. -+ -+Since 8.10.0 if this option is set for an HTTPS request then the application -+layer protocol version (ALPN) offered to the server is only HTTP/2. Prior to -+that both HTTP/1.1 and HTTP/2 were offered. -diff --git a/docs/cmdline-opts/http3.md b/docs/cmdline-opts/http3.md -index a1900655a..b5272a60f 100644 ---- a/docs/cmdline-opts/http3.md -+++ b/docs/cmdline-opts/http3.md -@@ -20,14 +20,16 @@ Example: - # `--http3` - - Attempt HTTP/3 to the host in the URL, but fallback to earlier HTTP versions --if the HTTP/3 connection establishment fails. HTTP/3 is only available for --HTTPS and not for HTTP URLs. -+if the HTTP/3 connection establishment fails or is slow. HTTP/3 is only -+available for HTTPS and not for HTTP URLs. - - This option allows a user to avoid using the Alt-Svc method of upgrading to --HTTP/3 when you know that the target speaks HTTP/3 on the given host and port. -+HTTP/3 when you know or suspect that the target speaks HTTP/3 on the given -+host and port. - - When asked to use HTTP/3, curl issues a separate attempt to use older HTTP - versions with a slight delay, so if the HTTP/3 transfer fails or is slow, curl --still tries to proceed with an older HTTP version. -+still tries to proceed with an older HTTP version. The fallback performs the -+regular negotiation between HTTP/1 and HTTP/2. - - Use --http3-only for similar functionality *without* a fallback. -diff --git a/docs/cmdline-opts/insecure.md b/docs/cmdline-opts/insecure.md -index b1c056b44..6b7009f25 100644 ---- a/docs/cmdline-opts/insecure.md -+++ b/docs/cmdline-opts/insecure.md -@@ -5,7 +5,7 @@ Long: insecure - Short: k - Help: Allow insecure server connections - Protocols: TLS SFTP SCP --Category: tls sftp scp -+Category: tls sftp scp ssh - Added: 7.10 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/interface.md b/docs/cmdline-opts/interface.md -index c938fd271..539e39272 100644 ---- a/docs/cmdline-opts/interface.md -+++ b/docs/cmdline-opts/interface.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: interface - Arg: --Help: Use network INTERFACE (or address) -+Help: Use network interface - Category: connection - Added: 7.3 - Multi: single -@@ -11,15 +11,41 @@ See-also: - - dns-interface - Example: - - --interface eth0 $URL -+ - --interface "host!10.0.0.1" $URL -+ - --interface "if!enp3s0" $URL - --- - - # `--interface` - --Perform an operation using a specified interface. You can enter interface --name, IP address or hostname. An example could look like: -+Perform the operation using a specified interface. You can enter interface -+name, IP address or hostname. If you prefer to be specific, you can use the -+following special syntax: - -- curl --interface eth0:1 https://www.example.com/ -+## if! - --On Linux it can be used to specify a **VRF**, but the binary needs to either --have **CAP_NET_RAW** or to be run as root. More information about Linux --**VRF**: https://www.kernel.org/doc/Documentation/networking/vrf.txt -+Interface name. If the provided name does not match an existing interface, -+curl returns with error 45. -+ -+## host! -+ -+IP address or hostname. -+ -+## ifhost!! -+ -+Interface name and IP address or hostname. This syntax requires libcurl 8.9.0 -+or later. -+ -+If the provided name does not match an existing interface, curl returns with -+error 45. -+ -+## -+ -+curl does not support using network interface names for this option on -+Windows. -+ -+That name resolve operation if a hostname is provided does **not** use -+DNS-over-HTTPS even if --doh-url is set. -+ -+On Linux this option can be used to specify a **VRF** (Virtual Routing and -+Forwarding) device, but the binary then needs to either have the -+**CAP_NET_RAW** capability set or to be run as root. -diff --git a/docs/cmdline-opts/ip-tos.md b/docs/cmdline-opts/ip-tos.md -new file mode 100644 -index 000000000..3d6473f31 ---- /dev/null -+++ b/docs/cmdline-opts/ip-tos.md -@@ -0,0 +1,27 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: ip-tos -+Arg: -+Help: Set IP Type of Service or Traffic Class -+Added: 8.9.0 -+Category: connection -+Protocols: All -+Multi: single -+See-also: -+ - tcp-nodelay -+ - vlan-priority -+Example: -+ - --ip-tos CS5 $URL -+--- -+ -+# `--ip-tos` -+ -+Set Type of Service (TOS) for IPv4 or Traffic Class for IPv6. -+ -+The values allowed for \ can be a numeric value between 1 and 255 -+or one of the following: -+ -+CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, AF11, AF12, AF13, AF21, AF22, AF23, -+AF31, AF32, AF33, AF41, AF42, AF43, EF, VOICE-ADMIT, ECT1, ECT0, CE, LE, -+LOWCOST, LOWDELAY, THROUGHPUT, RELIABILITY, MINCOST -diff --git a/docs/cmdline-opts/ipfs-gateway.md b/docs/cmdline-opts/ipfs-gateway.md -index 63429d83d..e5e8b10bd 100644 ---- a/docs/cmdline-opts/ipfs-gateway.md -+++ b/docs/cmdline-opts/ipfs-gateway.md -@@ -6,7 +6,7 @@ Arg: - Help: Gateway for IPFS - Protocols: IPFS - Added: 8.4.0 --Category: ipfs -+Category: curl - Multi: single - See-also: - - help -@@ -24,7 +24,8 @@ if a `~/.ipfs/gateway` file holding the gateway URL exists. - If you run a local IPFS node, this gateway is by default available under - `http://localhost:8080`. A full example URL would look like: - -- curl --ipfs-gateway http://localhost:8080 ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi -+ curl --ipfs-gateway http://localhost:8080 \ -+ ipfs://bafybeigagd5nmnn2iys2f3 - - There are many public IPFS gateways. See for example: - https://ipfs.github.io/public-gateway-checker/ -diff --git a/docs/cmdline-opts/json.md b/docs/cmdline-opts/json.md -index 8056e62e7..7763d81ee 100644 ---- a/docs/cmdline-opts/json.md -+++ b/docs/cmdline-opts/json.md -@@ -24,7 +24,7 @@ Example: - Sends the specified JSON data in a POST request to the HTTP server. --json - works as a shortcut for passing on these three options: - -- --data [arg] -+ --data-binary [arg] - --header "Content-Type: application/json" - --header "Accept: application/json" - -diff --git a/docs/cmdline-opts/keepalive-cnt.md b/docs/cmdline-opts/keepalive-cnt.md -new file mode 100644 -index 000000000..e56c976ec ---- /dev/null -+++ b/docs/cmdline-opts/keepalive-cnt.md -@@ -0,0 +1,27 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: keepalive-cnt -+Arg: -+Help: Maximum number of keepalive probes -+Added: 8.9.0 -+Category: connection -+Multi: single -+See-also: -+ - keepalive-time -+ - no-keepalive -+Example: -+ - --keepalive-cnt 3 $URL -+--- -+ -+# `--keepalive-cnt` -+ -+Set the maximum number of keepalive probes TCP should send but get no response -+before dropping the connection. This option is usually used in conjunction -+with --keepalive-time. -+ -+This option is supported on Linux, *BSD/macOS, Windows \>=10.0.16299, Solaris -+11.4, and recent AIX, HP-UX and more. This option has no effect if -+--no-keepalive is used. -+ -+If unspecified, the option defaults to 9. -diff --git a/docs/cmdline-opts/keepalive-time.md b/docs/cmdline-opts/keepalive-time.md -index 41c09031e..4b10ff6f4 100644 ---- a/docs/cmdline-opts/keepalive-time.md -+++ b/docs/cmdline-opts/keepalive-time.md -@@ -5,10 +5,11 @@ Long: keepalive-time - Arg: - Help: Interval time for keepalive probes - Added: 7.18.0 --Category: connection -+Category: connection timeout - Multi: single - See-also: - - no-keepalive -+ - keepalive-cnt - - max-time - Example: - - --keepalive-time 20 $URL -@@ -19,9 +20,11 @@ Example: - Set the time a connection needs to remain idle before sending keepalive probes - and the time between individual keepalive probes. It is currently effective on - operating systems offering the `TCP_KEEPIDLE` and `TCP_KEEPINTVL` socket --options (meaning Linux, recent AIX, HP-UX and more). Keepalive is used by the --TCP stack to detect broken networks on idle connections. The number of missed --keepalive probes before declaring the connection down is OS dependent and is --commonly 9 or 10. This option has no effect if --no-keepalive is used. -+options (meaning Linux, *BSD/macOS, Windows, Solaris, and recent AIX, HP-UX and more). -+Keepalive is used by the TCP stack to detect broken networks on idle connections. -+The number of missed keepalive probes before declaring the connection down is OS -+dependent and is commonly 8 (*BSD/macOS/AIX), 9 (Linux/AIX) or 5/10 (Windows), and -+this number can be changed by specifying the curl option `keepalive-cnt`. -+Note that this option has no effect if --no-keepalive is used. - - If unspecified, the option defaults to 60 seconds. -diff --git a/docs/cmdline-opts/libcurl.md b/docs/cmdline-opts/libcurl.md -index eeae596d0..e37e5aa0f 100644 ---- a/docs/cmdline-opts/libcurl.md -+++ b/docs/cmdline-opts/libcurl.md -@@ -5,7 +5,7 @@ Long: libcurl - Arg: - Help: Generate libcurl code for this command line - Added: 7.16.1 --Category: curl -+Category: curl global - Multi: single - Scope: global - See-also: -@@ -18,4 +18,4 @@ Example: - - Append this option to any ordinary curl command line, and you get - libcurl-using C source code written to the file that does the equivalent of --what your command-line operation does! -+what your command-line operation does. -diff --git a/docs/cmdline-opts/list-only.md b/docs/cmdline-opts/list-only.md -index 5d8dde65c..2800a8f79 100644 ---- a/docs/cmdline-opts/list-only.md -+++ b/docs/cmdline-opts/list-only.md -@@ -3,10 +3,10 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: list-only - Short: l --Protocols: FTP POP3 SFTP -+Protocols: FTP POP3 SFTP FILE - Help: List only mode - Added: 4.0 --Category: ftp pop3 sftp -+Category: ftp pop3 sftp file - Multi: boolean - See-also: - - quote -@@ -35,6 +35,9 @@ When retrieving a specific email from POP3, this switch forces a LIST command - to be performed instead of RETR. This is particularly useful if the user wants - to see if a specific message-id exists on the server and what size it is. - -+For FILE, this option has no effect yet as directories are always listed in -+this mode. -+ - Note: When combined with --request, this option can be used to send a UIDL - command instead, so the user may use the email's unique identifier rather than - its message-id to make the request. -diff --git a/docs/cmdline-opts/location-trusted.md b/docs/cmdline-opts/location-trusted.md -index 4f4e7def5..06458a467 100644 ---- a/docs/cmdline-opts/location-trusted.md -+++ b/docs/cmdline-opts/location-trusted.md -@@ -2,7 +2,7 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: location-trusted --Help: Like --location, but send auth to other hosts -+Help: As --location, but send secrets to other hosts - Protocols: HTTP - Category: http auth - Added: 7.10.4 -@@ -11,11 +11,16 @@ See-also: - - user - Example: - - --location-trusted -u user:password $URL -+ - --location-trusted -H "Cookie: session=abc" $URL - --- - - # `--location-trusted` - --Like --location, but allows sending the name + password to all hosts that the --site may redirect to. This may or may not introduce a security breach if the --site redirects you to a site to which you send your authentication info (which --is clear-text in the case of HTTP Basic authentication). -+Instructs curl to like --location follow HTTP redirects, but permits it to -+send credentials and other secrets along to other hosts than the initial one. -+ -+This may or may not introduce a security breach if the site redirects you to a -+site to which you send this sensitive data to. Another host means that one or -+more of hostname, protocol scheme or port number changed. -+ -+This option also allows curl to pass long cookies set explicitly with --header. -diff --git a/docs/cmdline-opts/location.md b/docs/cmdline-opts/location.md -index 62e3d470a..dbdcd5bd4 100644 ---- a/docs/cmdline-opts/location.md -+++ b/docs/cmdline-opts/location.md -@@ -20,11 +20,12 @@ Example: - If the server reports that the requested page has moved to a different - location (indicated with a Location: header and a 3XX response code), this - option makes curl redo the request on the new place. If used together with ----include or --head, headers from all requested pages are shown. -+--show-headers or --head, headers from all requested pages are shown. - --When authentication is used, curl only sends its credentials to the initial --host. If a redirect takes curl to a different host, it does not get the --user+password pass on. See also --location-trusted on how to change this. -+When authentication is used, or send cookie with `-H Cookie:`, curl only sends -+its credentials to the initial host. If a redirect takes curl to a different -+host, it does not get the credentials pass on. See --location-trusted on how -+to change this. - - Limit the amount of redirects to follow by using the --max-redirs option. - -diff --git a/docs/cmdline-opts/login-options.md b/docs/cmdline-opts/login-options.md -index fdeeda52a..fc8292a2b 100644 ---- a/docs/cmdline-opts/login-options.md -+++ b/docs/cmdline-opts/login-options.md -@@ -6,7 +6,7 @@ Arg: - Protocols: IMAP LDAP POP3 SMTP - Help: Server login options - Added: 7.34.0 --Category: imap pop3 smtp auth -+Category: imap pop3 smtp auth ldap - Multi: single - See-also: - - user -diff --git a/docs/cmdline-opts/mail-auth.md b/docs/cmdline-opts/mail-auth.md -index 3692c1596..deabb38b9 100644 ---- a/docs/cmdline-opts/mail-auth.md -+++ b/docs/cmdline-opts/mail-auth.md -@@ -12,7 +12,7 @@ See-also: - - mail-rcpt - - mail-from - Example: -- - --mail-auth user@example.come -T mail smtp://example.com/ -+ - --mail-auth user@example.com -T mail smtp://example.com/ - --- - - # `--mail-auth` -diff --git a/docs/cmdline-opts/max-filesize.md b/docs/cmdline-opts/max-filesize.md -index 998359cf7..cf2ac6537 100644 ---- a/docs/cmdline-opts/max-filesize.md -+++ b/docs/cmdline-opts/max-filesize.md -@@ -16,9 +16,11 @@ Example: - - # `--max-filesize` - --Specify the maximum size (in bytes) of a file to download. If the file --requested is larger than this value, the transfer does not start and curl --returns with exit code 63. -+When set to a non-zero value, it specifies the maximum size (in bytes) of a -+file to download. If the file requested is larger than this value, the -+transfer does not start and curl returns with exit code 63. -+ -+Setting the maximum value to zero disables the limit. - - A size modifier may be used. For example, Appending 'k' or 'K' counts the - number as kilobytes, 'm' or 'M' makes it megabytes, while 'g' or 'G' makes it -diff --git a/docs/cmdline-opts/max-time.md b/docs/cmdline-opts/max-time.md -index 9102442aa..dd5fb23ae 100644 ---- a/docs/cmdline-opts/max-time.md -+++ b/docs/cmdline-opts/max-time.md -@@ -5,7 +5,7 @@ Long: max-time - Short: m - Arg: - Help: Maximum time allowed for transfer --Category: connection -+Category: connection timeout - Added: 4.0 - Multi: single - See-also: -@@ -26,5 +26,5 @@ If you enable retrying the transfer (--retry) then the maximum time counter is - reset each time the transfer is retried. You can use --retry-max-time to limit - the retry time. - --The decimal value needs to provided using a dot (.) as decimal separator - not --the local version even if it might be using another separator. -+The decimal value needs to be provided using a dot (.) as decimal separator - -+not the local version even if it might be using another separator. -diff --git a/docs/cmdline-opts/metalink.md b/docs/cmdline-opts/metalink.md -index 0c39b46ed..d3d3e2574 100644 ---- a/docs/cmdline-opts/metalink.md -+++ b/docs/cmdline-opts/metalink.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: metalink - Help: Process given URLs as metalink XML file - Added: 7.27.0 --Category: misc -+Category: deprecated - Multi: single - See-also: - - parallel -diff --git a/docs/cmdline-opts/mptcp.md b/docs/cmdline-opts/mptcp.md -new file mode 100644 -index 000000000..698b69370 ---- /dev/null -+++ b/docs/cmdline-opts/mptcp.md -@@ -0,0 +1,31 @@ -+--- -+c: Copyright (C) Dorian Craps, -+SPDX-License-Identifier: curl -+Long: mptcp -+Added: 8.9.0 -+Help: Enable Multipath TCP -+Category: connection -+Multi: boolean -+See-also: -+ - tcp-fastopen -+Example: -+ - --mptcp $URL -+--- -+ -+# `--mptcp` -+ -+Enables the use of Multipath TCP (MPTCP) for connections. MPTCP is an extension -+to the standard TCP that allows multiple TCP streams over different network -+paths between the same source and destination. This can enhance bandwidth and -+improve reliability by using multiple paths simultaneously. -+ -+MPTCP is beneficial in networks where multiple paths exist between clients and -+servers, such as mobile networks where a device may switch between WiFi and -+cellular data or in wired networks with multiple Internet Service Providers. -+ -+This option is currently only supported on Linux starting from kernel 5.6. Only -+TCP connections are modified, hence this option does not effect HTTP/3 (QUIC) -+or UDP connections. -+ -+The server curl connects to must also support MPTCP. If not, the connection -+seamlessly falls back to TCP. -diff --git a/docs/cmdline-opts/netrc-file.md b/docs/cmdline-opts/netrc-file.md -index 841f23c48..3df72ce14 100644 ---- a/docs/cmdline-opts/netrc-file.md -+++ b/docs/cmdline-opts/netrc-file.md -@@ -6,7 +6,7 @@ Help: Specify FILE for netrc - Arg: - Added: 7.21.5 - Mutexed: netrc --Category: curl -+Category: auth - Multi: single - See-also: - - netrc -diff --git a/docs/cmdline-opts/netrc-optional.md b/docs/cmdline-opts/netrc-optional.md -index 6aa76954a..9b9c068c8 100644 ---- a/docs/cmdline-opts/netrc-optional.md -+++ b/docs/cmdline-opts/netrc-optional.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: netrc-optional - Help: Use either .netrc or URL - Mutexed: netrc --Category: curl -+Category: auth - Added: 7.9.8 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/netrc.md b/docs/cmdline-opts/netrc.md -index 4c07f9b75..26e1ccd21 100644 ---- a/docs/cmdline-opts/netrc.md -+++ b/docs/cmdline-opts/netrc.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: netrc - Short: n - Help: Must read .netrc for username and password --Category: curl -+Category: auth - Added: 4.6 - Mutexed: netrc-file netrc-optional - Multi: boolean -diff --git a/docs/cmdline-opts/next.md b/docs/cmdline-opts/next.md -index 2cf65c65a..cb67e907f 100644 ---- a/docs/cmdline-opts/next.md -+++ b/docs/cmdline-opts/next.md -@@ -7,7 +7,7 @@ Tags: - Protocols: - Added: 7.36.0 - Magic: divider --Help: Make next URL use its separate set of options -+Help: Make next URL use separate options - Category: curl - Multi: append - See-also: -diff --git a/docs/cmdline-opts/no-buffer.md b/docs/cmdline-opts/no-buffer.md -index 41328b165..e0860155c 100644 ---- a/docs/cmdline-opts/no-buffer.md -+++ b/docs/cmdline-opts/no-buffer.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: no-buffer - Short: N - Help: Disable buffering of the output stream --Category: curl -+Category: output - Added: 6.5 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/no-clobber.md b/docs/cmdline-opts/no-clobber.md -index 58646224c..690900563 100644 ---- a/docs/cmdline-opts/no-clobber.md -+++ b/docs/cmdline-opts/no-clobber.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: no-clobber - Help: Do not overwrite files that already exist --Category: curl output -+Category: output - Added: 7.83.0 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/no-keepalive.md b/docs/cmdline-opts/no-keepalive.md -index 1829e8c4e..2c2115fe0 100644 ---- a/docs/cmdline-opts/no-keepalive.md -+++ b/docs/cmdline-opts/no-keepalive.md -@@ -8,6 +8,7 @@ Added: 7.18.0 - Multi: boolean - See-also: - - keepalive-time -+ - keepalive-cnt - Example: - - --no-keepalive $URL - --- -diff --git a/docs/cmdline-opts/no-npn.md b/docs/cmdline-opts/no-npn.md -index d8ad6a251..dbb69e91b 100644 ---- a/docs/cmdline-opts/no-npn.md -+++ b/docs/cmdline-opts/no-npn.md -@@ -8,7 +8,7 @@ Added: 7.36.0 - Mutexed: - Requires: TLS - Help: Disable the NPN TLS extension --Category: tls http -+Category: deprecated - Multi: boolean - See-also: - - no-alpn -diff --git a/docs/cmdline-opts/ntlm-wb.md b/docs/cmdline-opts/ntlm-wb.md -index c5bcd4bfd..3a1d35cb1 100644 ---- a/docs/cmdline-opts/ntlm-wb.md -+++ b/docs/cmdline-opts/ntlm-wb.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: ntlm-wb - Help: HTTP NTLM authentication with winbind - Protocols: HTTP --Category: auth http -+Category: deprecated - Added: 7.22.0 - Multi: mutex - See-also: -@@ -16,5 +16,7 @@ Example: - - # `--ntlm-wb` - --Enables NTLM much in the style --ntlm does, but hand over the authentication --to the separate binary `ntlmauth` application that is executed when needed. -+Deprecated option (added in 8.8.0). -+ -+Enabled NTLM much in the style --ntlm does, but handed over the authentication -+to a separate executable that was executed when needed. -diff --git a/docs/cmdline-opts/oauth2-bearer.md b/docs/cmdline-opts/oauth2-bearer.md -index ee9ec5dcc..b66477fc7 100644 ---- a/docs/cmdline-opts/oauth2-bearer.md -+++ b/docs/cmdline-opts/oauth2-bearer.md -@@ -5,7 +5,7 @@ Long: oauth2-bearer - Help: OAuth 2 Bearer Token - Arg: - Protocols: IMAP LDAP POP3 SMTP HTTP --Category: auth -+Category: auth imap pop3 smtp ldap - Added: 7.33.0 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/output-dir.md b/docs/cmdline-opts/output-dir.md -index 04d780f29..468ecc8a1 100644 ---- a/docs/cmdline-opts/output-dir.md -+++ b/docs/cmdline-opts/output-dir.md -@@ -5,7 +5,7 @@ Long: output-dir - Arg: - Help: Directory to save files in - Added: 7.73.0 --Category: curl -+Category: output - Multi: single - See-also: - - remote-name -diff --git a/docs/cmdline-opts/output.md b/docs/cmdline-opts/output.md -index 53f658327..48360a498 100644 ---- a/docs/cmdline-opts/output.md -+++ b/docs/cmdline-opts/output.md -@@ -5,9 +5,9 @@ Long: output - Arg: - Short: o - Help: Write to file instead of stdout --Category: important curl -+Category: important output - Added: 4.0 --Multi: append -+Multi: per-URL - See-also: - - remote-name - - remote-name-all -diff --git a/docs/cmdline-opts/parallel-immediate.md b/docs/cmdline-opts/parallel-immediate.md -index f93a355f2..4d7a3ad51 100644 ---- a/docs/cmdline-opts/parallel-immediate.md -+++ b/docs/cmdline-opts/parallel-immediate.md -@@ -2,9 +2,9 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: parallel-immediate --Help: Do not wait for multiplexing (with --parallel) -+Help: Do not wait for multiplexing - Added: 7.68.0 --Category: connection curl -+Category: connection curl global - Multi: boolean - Scope: global - See-also: -@@ -16,7 +16,10 @@ Example: - - # `--parallel-immediate` - --When doing parallel transfers, this option instructs curl that it should --rather prefer opening up more connections in parallel at once rather than --waiting to see if new transfers can be added as multiplexed streams on another --connection. -+When doing parallel transfers, this option instructs curl to prefer opening up -+more connections in parallel at once rather than waiting to see if new -+transfers can be added as multiplexed streams on another connection. -+ -+By default, without this option set, curl prefers to wait a little and -+multiplex new transfers over existing connections. It keeps the number of -+connections low at the expense of risking a slightly slower transfer startup. -diff --git a/docs/cmdline-opts/parallel-max.md b/docs/cmdline-opts/parallel-max.md -index f3d2ad198..6b3684b8f 100644 ---- a/docs/cmdline-opts/parallel-max.md -+++ b/docs/cmdline-opts/parallel-max.md -@@ -5,8 +5,9 @@ Long: parallel-max - Arg: - Help: Maximum concurrency for parallel transfers - Added: 7.66.0 --Category: connection curl -+Category: connection curl global - Multi: single -+Scope: global - See-also: - - parallel - Example: -@@ -18,7 +19,4 @@ Example: - When asked to do parallel transfers, using --parallel, this option controls - the maximum amount of transfers to do simultaneously. - --This option is global and does not need to be specified for each use of ----next. -- --The default is 50. -+The default is 50. 300 is the largest supported value. -diff --git a/docs/cmdline-opts/parallel.md b/docs/cmdline-opts/parallel.md -index f67598a0b..fb9221bc6 100644 ---- a/docs/cmdline-opts/parallel.md -+++ b/docs/cmdline-opts/parallel.md -@@ -5,17 +5,28 @@ Short: Z - Long: parallel - Help: Perform transfers in parallel - Added: 7.66.0 --Category: connection curl -+Category: connection curl global - Multi: boolean - Scope: global - See-also: - - next - - verbose -+ - parallel-max -+ - parallel-immediate - Example: - - --parallel $URL -o file1 $URL -o file2 - --- - - # `--parallel` - --Makes curl perform its transfers in parallel as compared to the regular serial --manner. -+Makes curl perform all transfers in parallel as compared to the regular serial -+manner. Parallel transfer means that curl runs up to N concurrent transfers -+simultaneously and if there are more than N transfers to handle, it starts new -+ones when earlier transfers finish. -+ -+With parallel transfers, the progress meter output is different than when -+doing serial transfers, as it then displays the transfer status for multiple -+transfers in a single line. -+ -+The maximum amount of concurrent transfers is set with --parallel-max and it -+defaults to 50. -diff --git a/docs/cmdline-opts/pass.md b/docs/cmdline-opts/pass.md -index a0d94563e..98bc35b24 100644 ---- a/docs/cmdline-opts/pass.md -+++ b/docs/cmdline-opts/pass.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: pass - Arg: --Help: Pass phrase for the private key -+Help: Passphrase for the private key - Protocols: SSH TLS - Category: ssh tls auth - Added: 7.9.3 -diff --git a/docs/cmdline-opts/pinnedpubkey.md b/docs/cmdline-opts/pinnedpubkey.md -index 53c79912a..d21a18f69 100644 ---- a/docs/cmdline-opts/pinnedpubkey.md -+++ b/docs/cmdline-opts/pinnedpubkey.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: pinnedpubkey - Arg: --Help: FILE/HASHES Public key to verify peer against -+Help: Public key to verify peer against - Protocols: TLS - Category: tls - Added: 7.39.0 -@@ -33,12 +33,13 @@ together then the peer is still verified by public key. - PEM/DER support: - - OpenSSL and GnuTLS (added in 7.39.0), wolfSSL (added in 7.43.0), mbedTLS --(added in 7.47.0), Secure Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel --(7.58.1) -+(added in 7.47.0), Secure Transport macOS 10.7+/iOS 10+ (added in 7.54.1), -+Schannel (added in 7.58.1) - - sha256 support: - - OpenSSL, GnuTLS and wolfSSL (added in 7.44.0), mbedTLS (added in 7.47.0), --Secure Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel (7.58.1) -+Secure Transport macOS 10.7+/iOS 10+ (added in 7.54.1), Schannel -+(added in 7.58.1) - - Other SSL backends not supported. -diff --git a/docs/cmdline-opts/progress-bar.md b/docs/cmdline-opts/progress-bar.md -index 7b9c599b9..6f08d7f7c 100644 ---- a/docs/cmdline-opts/progress-bar.md -+++ b/docs/cmdline-opts/progress-bar.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Short: # - Long: progress-bar - Help: Display transfer progress as a bar --Category: verbose -+Category: verbose global - Added: 5.10 - Multi: boolean - Scope: global -diff --git a/docs/cmdline-opts/proto-redir.md b/docs/cmdline-opts/proto-redir.md -index 51fb7bd3a..9332f3f0d 100644 ---- a/docs/cmdline-opts/proto-redir.md -+++ b/docs/cmdline-opts/proto-redir.md -@@ -22,6 +22,6 @@ Example, allow only HTTP and HTTPS on redirect: - - curl --proto-redir -all,http,https http://example.com - --By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects (added in --7.65.2). Specifying *all* or *+all* enables all protocols on redirects, which --is not good for security. -+By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects -+(added in 7.65.2). Specifying *all* or *+all* enables all protocols on -+redirects, which is not good for security. -diff --git a/docs/cmdline-opts/proxy-ca-native.md b/docs/cmdline-opts/proxy-ca-native.md -index 6158b6cf6..e84dbd960 100644 ---- a/docs/cmdline-opts/proxy-ca-native.md -+++ b/docs/cmdline-opts/proxy-ca-native.md -@@ -10,9 +10,10 @@ Multi: boolean - See-also: - - cacert - - capath -+ - dump-ca-embed - - insecure - Example: -- - --ca-native $URL -+ - --proxy-ca-native $URL - --- - - # `--proxy-ca-native` -diff --git a/docs/cmdline-opts/proxy-cacert.md b/docs/cmdline-opts/proxy-cacert.md -index ec0dd9f14..682349a7e 100644 ---- a/docs/cmdline-opts/proxy-cacert.md -+++ b/docs/cmdline-opts/proxy-cacert.md -@@ -11,6 +11,7 @@ See-also: - - proxy-capath - - cacert - - capath -+ - dump-ca-embed - - proxy - Example: - - --proxy-cacert CA-file.txt -x https://proxy $URL -@@ -18,4 +19,10 @@ Example: - - # `--proxy-cacert` - --Same as --cacert but used in HTTPS proxy context. -+Use the specified certificate file to verify the HTTPS proxy. The file may -+contain multiple CA certificates. The certificate(s) must be in PEM format. -+ -+This allows you to use a different trust for the proxy compared to the remote -+server connected to via the proxy. -+ -+Equivalent to --cacert but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-capath.md b/docs/cmdline-opts/proxy-capath.md -index bc2c7b56f..3a3aabf10 100644 ---- a/docs/cmdline-opts/proxy-capath.md -+++ b/docs/cmdline-opts/proxy-capath.md -@@ -11,6 +11,7 @@ See-also: - - proxy-cacert - - proxy - - capath -+ - dump-ca-embed - Example: - - --proxy-capath /local/directory -x https://proxy $URL - --- -diff --git a/docs/cmdline-opts/proxy-cert-type.md b/docs/cmdline-opts/proxy-cert-type.md -index 3f46bb618..c2e8ed1ec 100644 ---- a/docs/cmdline-opts/proxy-cert-type.md -+++ b/docs/cmdline-opts/proxy-cert-type.md -@@ -9,10 +9,18 @@ Category: proxy tls - Multi: single - See-also: - - proxy-cert -+ - proxy-key - Example: - - --proxy-cert-type PEM --proxy-cert file -x https://proxy $URL - --- - - # `--proxy-cert-type` - --Same as --cert-type but used in HTTPS proxy context. -+Set type of the provided client certificate when using HTTPS proxy. PEM, DER, -+ENG and P12 are recognized types. -+ -+The default type depends on the TLS backend and is usually PEM, however for -+Secure Transport and Schannel it is P12. If --proxy-cert is a pkcs11: URI then -+ENG is the default type. -+ -+Equivalent to --cert-type but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-cert.md b/docs/cmdline-opts/proxy-cert.md -index 3068f3cd1..a588329d0 100644 ---- a/docs/cmdline-opts/proxy-cert.md -+++ b/docs/cmdline-opts/proxy-cert.md -@@ -8,6 +8,8 @@ Added: 7.52.0 - Category: proxy tls - Multi: single - See-also: -+ - proxy -+ - proxy-key - - proxy-cert-type - Example: - - --proxy-cert file -x https://proxy $URL -@@ -15,4 +17,10 @@ Example: - - # `--proxy-cert` - --Same as --cert but used in HTTPS proxy context. -+Use the specified client certificate file when communicating with an HTTPS -+proxy. The certificate must be in PKCS#12 format if using Secure Transport, or -+PEM format if using any other engine. If the optional password is not -+specified, it is queried for on the terminal. Use --proxy-key to provide the -+private key. -+ -+This option is the equivalent to --cert but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-ciphers.md b/docs/cmdline-opts/proxy-ciphers.md -index 065d44953..420e7563b 100644 ---- a/docs/cmdline-opts/proxy-ciphers.md -+++ b/docs/cmdline-opts/proxy-ciphers.md -@@ -3,24 +3,25 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: proxy-ciphers - Arg: --Help: SSL ciphers to use for proxy -+Help: TLS 1.2 (1.1, 1.0) ciphers to use for proxy -+Protocols: TLS - Added: 7.52.0 - Category: proxy tls - Multi: single - See-also: -+ - proxy-tls13-ciphers - - ciphers -- - curves - - proxy - Example: -- - --proxy-ciphers ECDHE-ECDSA-AES256-CCM8 -x https://proxy $URL -+ - --proxy-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 -x https://proxy $URL - --- - - # `--proxy-ciphers` - - Same as --ciphers but used in HTTPS proxy context. - --Specifies which ciphers to use in the connection to the HTTPS proxy. The list --of ciphers must specify valid ciphers. Read up on SSL cipher list details on --this URL: -+Specify which cipher suites to use in the connection to your HTTPS proxy when -+it negotiates TLS 1.2 (1.1, 1.0). The list of ciphers suites must specify -+valid ciphers. Read up on cipher suite details on this URL: - - https://curl.se/docs/ssl-ciphers.html -diff --git a/docs/cmdline-opts/proxy-crlfile.md b/docs/cmdline-opts/proxy-crlfile.md -index ab47fb0a0..726e44955 100644 ---- a/docs/cmdline-opts/proxy-crlfile.md -+++ b/docs/cmdline-opts/proxy-crlfile.md -@@ -16,4 +16,8 @@ Example: - - # `--proxy-crlfile` - --Same as --crlfile but used in HTTPS proxy context. -+Provide filename for a PEM formatted file with a Certificate Revocation List -+that specifies peer certificates that are considered revoked when -+communicating with an HTTPS proxy. -+ -+Equivalent to --crlfile but only used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-key-type.md b/docs/cmdline-opts/proxy-key-type.md -index 8740935b5..587c13c59 100644 ---- a/docs/cmdline-opts/proxy-key-type.md -+++ b/docs/cmdline-opts/proxy-key-type.md -@@ -16,4 +16,7 @@ Example: - - # `--proxy-key-type` - --Same as --key-type but used in HTTPS proxy context. -+Specify the private key file type your --proxy-key provided private key uses. -+DER, PEM, and ENG are supported. If not specified, PEM is assumed. -+ -+Equivalent to --key-type but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-key.md b/docs/cmdline-opts/proxy-key.md -index cfe507845..7caa636e3 100644 ---- a/docs/cmdline-opts/proxy-key.md -+++ b/docs/cmdline-opts/proxy-key.md -@@ -16,4 +16,6 @@ Example: - - # `--proxy-key` - --Same as --key but used in HTTPS proxy context. -+Specify the filename for your private key when using client certificates with -+your HTTPS proxy. This option is the equivalent to --key but used in HTTPS -+proxy context. -diff --git a/docs/cmdline-opts/proxy-negotiate.md b/docs/cmdline-opts/proxy-negotiate.md -index 9bedf5dc4..0285155c6 100644 ---- a/docs/cmdline-opts/proxy-negotiate.md -+++ b/docs/cmdline-opts/proxy-negotiate.md -@@ -9,6 +9,7 @@ Multi: mutex - See-also: - - proxy-anyauth - - proxy-basic -+ - proxy-service-name - Example: - - --proxy-negotiate --proxy-user user:passwd -x proxy $URL - --- -diff --git a/docs/cmdline-opts/proxy-ntlm.md b/docs/cmdline-opts/proxy-ntlm.md -index f8375a620..e403f98ec 100644 ---- a/docs/cmdline-opts/proxy-ntlm.md -+++ b/docs/cmdline-opts/proxy-ntlm.md -@@ -9,6 +9,7 @@ Multi: mutex - See-also: - - proxy-negotiate - - proxy-anyauth -+ - proxy-user - Example: - - --proxy-ntlm --proxy-user user:passwd -x http://proxy $URL - --- -diff --git a/docs/cmdline-opts/proxy-pass.md b/docs/cmdline-opts/proxy-pass.md -index feba6e083..88cefd54c 100644 ---- a/docs/cmdline-opts/proxy-pass.md -+++ b/docs/cmdline-opts/proxy-pass.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: proxy-pass - Arg: --Help: Pass phrase for the private key for HTTPS proxy -+Help: Passphrase for private key for HTTPS proxy - Added: 7.52.0 - Category: proxy tls auth - Multi: single -@@ -16,4 +16,6 @@ Example: - - # `--proxy-pass` - --Same as --pass but used in HTTPS proxy context. -+Passphrase for the private key for HTTPS proxy client certificate. -+ -+Equivalent to --pass but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-pinnedpubkey.md b/docs/cmdline-opts/proxy-pinnedpubkey.md -index 6f0b52d3e..df0b0bb90 100644 ---- a/docs/cmdline-opts/proxy-pinnedpubkey.md -+++ b/docs/cmdline-opts/proxy-pinnedpubkey.md -@@ -27,3 +27,5 @@ When negotiating a TLS or SSL connection, the server sends a certificate - indicating its identity. A public key is extracted from this certificate and - if it does not exactly match the public key provided to this option, curl - aborts the connection before sending or receiving any data. -+ -+Before curl 8.10.0 this option did not work due to a bug. -diff --git a/docs/cmdline-opts/proxy-service-name.md b/docs/cmdline-opts/proxy-service-name.md -index 534222f44..b3d665d8b 100644 ---- a/docs/cmdline-opts/proxy-service-name.md -+++ b/docs/cmdline-opts/proxy-service-name.md -@@ -10,10 +10,11 @@ Multi: single - See-also: - - service-name - - proxy -+ - proxy-negotiate - Example: - - --proxy-service-name "shrubbery" -x proxy $URL - --- - - # `--proxy-service-name` - --Set the service name for proxy negotiation. -+Set the service name for SPNEGO when doing proxy authentication. -diff --git a/docs/cmdline-opts/proxy-ssl-allow-beast.md b/docs/cmdline-opts/proxy-ssl-allow-beast.md -index f2deedbb5..089038dec 100644 ---- a/docs/cmdline-opts/proxy-ssl-allow-beast.md -+++ b/docs/cmdline-opts/proxy-ssl-allow-beast.md -@@ -2,7 +2,7 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: proxy-ssl-allow-beast --Help: Allow security flaw for interop for HTTPS proxy -+Help: Allow this security flaw for HTTPS proxy - Added: 7.52.0 - Category: proxy tls - Multi: boolean -@@ -15,4 +15,15 @@ Example: - - # `--proxy-ssl-allow-beast` - --Same as --ssl-allow-beast but used in HTTPS proxy context. -+Do not work around a security flaw in the TLS1.0 protocol known as BEAST when -+communicating to an HTTPS proxy. If this option is not used, the TLS layer may -+use workarounds known to cause interoperability problems with some older -+server implementations. -+ -+This option only changes how curl does TLS 1.0 with an HTTPS proxy and has no -+effect on later TLS versions. -+ -+**WARNING**: this option loosens the TLS security, and by using this flag you -+ask for exactly that. -+ -+Equivalent to --ssl-allow-beast but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-tls13-ciphers.md b/docs/cmdline-opts/proxy-tls13-ciphers.md -index 002fd0b0f..72bae4e75 100644 ---- a/docs/cmdline-opts/proxy-tls13-ciphers.md -+++ b/docs/cmdline-opts/proxy-tls13-ciphers.md -@@ -2,28 +2,32 @@ - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: proxy-tls13-ciphers --Arg: -+Arg: - help: TLS 1.3 proxy cipher suites - Protocols: TLS - Category: proxy tls - Added: 7.61.0 - Multi: single - See-also: -- - tls13-ciphers -- - curves - - proxy-ciphers -+ - tls13-ciphers -+ - proxy - Example: - - --proxy-tls13-ciphers TLS_AES_128_GCM_SHA256 -x proxy $URL - --- - - # `--proxy-tls13-ciphers` - -+Same as --tls13-ciphers but used in HTTPS proxy context. -+ - Specify which cipher suites to use in the connection to your HTTPS proxy when - it negotiates TLS 1.3. The list of ciphers suites must specify valid ciphers. - Read up on TLS 1.3 cipher suite details on this URL: - - https://curl.se/docs/ssl-ciphers.html - --This option is currently used only when curl is built to use OpenSSL 1.1.1 or --later. If you are using a different SSL backend you can try setting TLS 1.3 --cipher suites by using the --proxy-ciphers option. -+This option is used when curl is built to use OpenSSL 1.1.1 or later, -+Schannel, wolfSSL, or mbedTLS 3.6.0 or later. -+ -+Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites were set -+by using the --proxy-ciphers option. -diff --git a/docs/cmdline-opts/proxy-tlsauthtype.md b/docs/cmdline-opts/proxy-tlsauthtype.md -index 067e4c598..684a7d55e 100644 ---- a/docs/cmdline-opts/proxy-tlsauthtype.md -+++ b/docs/cmdline-opts/proxy-tlsauthtype.md -@@ -10,10 +10,15 @@ Multi: single - See-also: - - proxy - - proxy-tlsuser -+ - proxy-tlspassword - Example: - - --proxy-tlsauthtype SRP -x https://proxy $URL - --- - - # `--proxy-tlsauthtype` - --Same as --tlsauthtype but used in HTTPS proxy context. -+Set TLS authentication type with HTTPS proxy. The only supported option is -+`SRP`, for TLS-SRP (RFC 5054). This option works only if the underlying -+libcurl is built with TLS-SRP support. -+ -+Equivalent to --tlsauthtype but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-tlspassword.md b/docs/cmdline-opts/proxy-tlspassword.md -index 3c6d06c6a..fe9ae7d2e 100644 ---- a/docs/cmdline-opts/proxy-tlspassword.md -+++ b/docs/cmdline-opts/proxy-tlspassword.md -@@ -16,4 +16,10 @@ Example: - - # `--proxy-tlspassword` - --Same as --tlspassword but used in HTTPS proxy context. -+Set password to use with the TLS authentication method specified with -+--proxy-tlsauthtype when using HTTPS proxy. Requires that --proxy-tlsuser is -+set. -+ -+This option does not work with TLS 1.3. -+ -+Equivalent to --tlspassword but used in HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy-tlsuser.md b/docs/cmdline-opts/proxy-tlsuser.md -index 1c626ee75..351770111 100644 ---- a/docs/cmdline-opts/proxy-tlsuser.md -+++ b/docs/cmdline-opts/proxy-tlsuser.md -@@ -16,4 +16,8 @@ Example: - - # `--proxy-tlsuser` - --Same as --tlsuser but used in HTTPS proxy context. -+Set username for use for HTTPS proxy with the TLS authentication method -+specified with --proxy-tlsauthtype. Requires that --proxy-tlspassword also is -+set. -+ -+This option does not work with TLS 1.3. -diff --git a/docs/cmdline-opts/proxy-tlsv1.md b/docs/cmdline-opts/proxy-tlsv1.md -index 0dda72f4b..7b322e3a3 100644 ---- a/docs/cmdline-opts/proxy-tlsv1.md -+++ b/docs/cmdline-opts/proxy-tlsv1.md -@@ -14,4 +14,7 @@ Example: - - # `--proxy-tlsv1` - --Same as --tlsv1 but used in HTTPS proxy context. -+Use at least TLS version 1.x when negotiating with an HTTPS proxy. That means -+TLS version 1.0 or higher -+ -+Equivalent to --tlsv1 but for an HTTPS proxy context. -diff --git a/docs/cmdline-opts/proxy.md b/docs/cmdline-opts/proxy.md -index 51f638c67..afaa29837 100644 ---- a/docs/cmdline-opts/proxy.md -+++ b/docs/cmdline-opts/proxy.md -@@ -28,7 +28,7 @@ Unix domain sockets are supported for socks proxy. Set localhost for the host - part. e.g. socks5h://localhost/path/to/socket.sock - - HTTPS proxy support works set with the https:// protocol prefix for OpenSSL --and GnuTLS (added in 7.52.0). It also works for BearSSL, mbedTLS, rustls, -+and GnuTLS (added in 7.52.0). It also works for BearSSL, mbedTLS, Rustls, - Schannel, Secure Transport and wolfSSL (added in 7.87.0). - - Unrecognized and unsupported proxy protocols cause an error (added in 7.52.0). -@@ -56,3 +56,7 @@ password. - - When a proxy is used, the active FTP mode as set with --ftp-port, cannot be - used. -+ -+Doing FTP over an HTTP proxy without --proxytunnel makes curl do HTTP with an -+FTP URL over the proxy. For such transfers, common FTP specific options do not -+work, including --ftp-ssl-reqd and --ftp-ssl-control. -diff --git a/docs/cmdline-opts/pubkey.md b/docs/cmdline-opts/pubkey.md -index 94e50e4e9..373d113c3 100644 ---- a/docs/cmdline-opts/pubkey.md -+++ b/docs/cmdline-opts/pubkey.md -@@ -5,7 +5,7 @@ Long: pubkey - Arg: - Protocols: SFTP SCP - Help: SSH Public key filename --Category: sftp scp auth -+Category: sftp scp ssh auth - Added: 7.16.2 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/random-file.md b/docs/cmdline-opts/random-file.md -index 0f564d9d7..e2c8624ab 100644 ---- a/docs/cmdline-opts/random-file.md -+++ b/docs/cmdline-opts/random-file.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: random-file - Arg: - Help: File for reading random data from --Category: misc -+Category: deprecated - Added: 7.7 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/range.md b/docs/cmdline-opts/range.md -index abfdf216f..c2cee2e1f 100644 ---- a/docs/cmdline-opts/range.md -+++ b/docs/cmdline-opts/range.md -@@ -42,7 +42,7 @@ specifies two separate 100-byte ranges(*) (HTTP) - ## - - (*) = NOTE that these make the server reply with a multipart response, which --is returned as-is by curl! Parsing or otherwise transforming this response is -+is returned as-is by curl. Parsing or otherwise transforming this response is - the responsibility of the caller. - - Only digit characters (0-9) are valid in the 'start' and 'stop' fields of the -diff --git a/docs/cmdline-opts/rate.md b/docs/cmdline-opts/rate.md -index fb2901e7e..6de65165d 100644 ---- a/docs/cmdline-opts/rate.md -+++ b/docs/cmdline-opts/rate.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: rate - Arg: - Help: Request rate for serial transfers --Category: connection -+Category: connection global - Added: 7.84.0 - Multi: single - Scope: global -@@ -40,3 +40,7 @@ more than 1000 per second, it instead runs unrestricted. - - When retrying transfers, enabled with --retry, the separate retry delay logic - is used and not this setting. -+ -+Starting in version 8.10.0, you can specify number of time units in the rate -+expression. Make curl do no more than 5 transfers per 15 seconds with "5/15s" -+or limit it to 3 transfers per 4 hours with "3/4h". No spaces allowed. -diff --git a/docs/cmdline-opts/remote-name.md b/docs/cmdline-opts/remote-name.md -index 5d2fcdcb2..e39dd51ae 100644 ---- a/docs/cmdline-opts/remote-name.md -+++ b/docs/cmdline-opts/remote-name.md -@@ -6,13 +6,14 @@ Short: O - Help: Write output to file named as remote file - Category: important output - Added: 4.0 --Multi: append -+Multi: per-URL - See-also: - - remote-name-all - - output-dir - - remote-header-name - Example: - - -O https://example.com/filename -+ - -O https://example.com/filename -O https://example.com/file2 - --- - - # `--remote-name` -@@ -34,3 +35,8 @@ There is no URL decoding done on the filename. If it has %20 or other URL - encoded parts of the name, they end up as-is as filename. - - You may use this option as many times as the number of URLs you have. -+ -+Before curl 8.10.0, curl returned an error if the URL ended with a slash, -+which means that there is no filename part in the URL. Starting in 8.10.0, -+curl sets the filename to the last directory part of the URL or if that also -+is missing to `curl_response` (without extension) for this situation. -diff --git a/docs/cmdline-opts/remove-on-error.md b/docs/cmdline-opts/remove-on-error.md -index b0064ae31..4f9cf90de 100644 ---- a/docs/cmdline-opts/remove-on-error.md -+++ b/docs/cmdline-opts/remove-on-error.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: remove-on-error - Help: Remove output file on errors --Category: curl -+Category: output - Added: 7.83.0 - Multi: boolean - See-also: -diff --git a/docs/cmdline-opts/request.md b/docs/cmdline-opts/request.md -index 4a6304c1b..86cf10dea 100644 ---- a/docs/cmdline-opts/request.md -+++ b/docs/cmdline-opts/request.md -@@ -5,7 +5,7 @@ Long: request - Short: X - Arg: - Help: Specify request method to use --Category: connection -+Category: connection pop3 ftp imap smtp - Added: 6.0 - Multi: single - See-also: -@@ -19,7 +19,7 @@ Example: - - Change the method to use when starting the transfer. - --curl passes on the verbatim string you give it its the request without any -+curl passes on the verbatim string you give it in the request without any - filter or other safe guards. That includes white space and control characters. - - ## HTTP -diff --git a/docs/cmdline-opts/resolve.md b/docs/cmdline-opts/resolve.md -index ca1f930fc..2b71d9a59 100644 ---- a/docs/cmdline-opts/resolve.md -+++ b/docs/cmdline-opts/resolve.md -@@ -37,9 +37,8 @@ parallel transfers with a lot of files. In such cases, if this option is used - curl tries to resolve the host as it normally would once the timeout has - expired. - --Support for providing the IP address within [brackets] was added in 7.57.0. -- --Support for providing multiple IP addresses per entry was added in 7.59.0. -+To redirect connects from a specific hostname or any hostname, independently -+of port number, consider the --connect-to option. - - Support for resolving with wildcard was added in 7.64.0. - -diff --git a/docs/cmdline-opts/retry-delay.md b/docs/cmdline-opts/retry-delay.md -index b2a405b63..fcee1767a 100644 ---- a/docs/cmdline-opts/retry-delay.md -+++ b/docs/cmdline-opts/retry-delay.md -@@ -5,7 +5,7 @@ Long: retry-delay - Arg: - Help: Wait time between retries - Added: 7.12.3 --Category: curl -+Category: curl timeout - Multi: single - See-also: - - retry -diff --git a/docs/cmdline-opts/retry-max-time.md b/docs/cmdline-opts/retry-max-time.md -index f7346475b..e95a381a4 100644 ---- a/docs/cmdline-opts/retry-max-time.md -+++ b/docs/cmdline-opts/retry-max-time.md -@@ -5,7 +5,7 @@ Long: retry-max-time - Arg: - Help: Retry only within this period - Added: 7.12.3 --Category: curl -+Category: curl timeout - Multi: single - See-also: - - retry -diff --git a/docs/cmdline-opts/service-name.md b/docs/cmdline-opts/service-name.md -index b39bad4f1..f98409aa2 100644 ---- a/docs/cmdline-opts/service-name.md -+++ b/docs/cmdline-opts/service-name.md -@@ -5,7 +5,7 @@ Long: service-name - Help: SPNEGO service name - Arg: - Added: 7.43.0 --Category: misc -+Category: auth - Multi: single - See-also: - - negotiate -diff --git a/docs/cmdline-opts/show-error.md b/docs/cmdline-opts/show-error.md -index 0517c37bb..aaf865bc0 100644 ---- a/docs/cmdline-opts/show-error.md -+++ b/docs/cmdline-opts/show-error.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: show-error - Short: S - Help: Show error even when -s is used --Category: curl -+Category: curl global - Added: 5.9 - Multi: boolean - Scope: global -diff --git a/docs/cmdline-opts/show-headers.md b/docs/cmdline-opts/show-headers.md -new file mode 100644 -index 000000000..126610f7c ---- /dev/null -+++ b/docs/cmdline-opts/show-headers.md -@@ -0,0 +1,29 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: show-headers -+Short: i -+Help: Show response headers in output -+Protocols: HTTP FTP -+Category: important verbose output -+Added: 4.8 -+Multi: boolean -+See-also: -+ - verbose -+Example: -+ - -i $URL -+--- -+ -+# `--show-headers` -+ -+Show response headers in the output. HTTP response headers can include things -+like server name, cookies, date of the document, HTTP version and more. With -+non-HTTP protocols, the "headers" are other server communication. -+ -+To view the request headers, consider the --verbose option. -+ -+Prior to 7.75.0 curl did not print the headers if --fail was used in -+combination with this option and there was error reported by server. -+ -+This option was called --include before 8.10.0. The previous name remains -+functional. -diff --git a/docs/cmdline-opts/skip-existing.md b/docs/cmdline-opts/skip-existing.md -new file mode 100644 -index 000000000..cfb7c2f95 ---- /dev/null -+++ b/docs/cmdline-opts/skip-existing.md -@@ -0,0 +1,22 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: skip-existing -+Help: Skip download if local file already exists -+Category: curl output -+Added: 8.10.0 -+Multi: boolean -+See-also: -+ - output -+ - remote-name -+ - no-clobber -+Example: -+ - --skip-existing --output local/dir/file $URL -+--- -+ -+# `--skip-existing` -+ -+If there is a local file present when a download is requested, the operation -+is skipped. Note that curl cannot know if the local file was previously -+downloaded fine, or if it is incomplete etc, it just knows if there is a -+filename present in the file system or not and it skips the transfer if it is. -diff --git a/docs/cmdline-opts/socks4.md b/docs/cmdline-opts/socks4.md -index e74fa787c..99a7fc922 100644 ---- a/docs/cmdline-opts/socks4.md -+++ b/docs/cmdline-opts/socks4.md -@@ -21,7 +21,7 @@ Use the specified SOCKS4 proxy. If the port number is not specified, it is - assumed at port 1080. Using this socket type make curl resolve the hostname - and passing the address on to the proxy. - --To specify proxy on a unix domain socket, use localhost for host, e.g. -+To specify proxy on a Unix domain socket, use localhost for host, e.g. - `socks4://localhost/path/to/socket.sock` - - This option overrides any previous use of --proxy, as they are mutually -diff --git a/docs/cmdline-opts/socks4a.md b/docs/cmdline-opts/socks4a.md -index 49fb9a275..04d60b81b 100644 ---- a/docs/cmdline-opts/socks4a.md -+++ b/docs/cmdline-opts/socks4a.md -@@ -20,7 +20,7 @@ Example: - Use the specified SOCKS4a proxy. If the port number is not specified, it is - assumed at port 1080. This asks the proxy to resolve the hostname. - --To specify proxy on a unix domain socket, use localhost for host, e.g. -+To specify proxy on a Unix domain socket, use localhost for host, e.g. - `socks4a://localhost/path/to/socket.sock` - - This option overrides any previous use of --proxy, as they are mutually -diff --git a/docs/cmdline-opts/socks5-hostname.md b/docs/cmdline-opts/socks5-hostname.md -index 1a5e4c1b5..0ea2ed739 100644 ---- a/docs/cmdline-opts/socks5-hostname.md -+++ b/docs/cmdline-opts/socks5-hostname.md -@@ -19,7 +19,7 @@ Example: - Use the specified SOCKS5 proxy (and let the proxy resolve the hostname). If - the port number is not specified, it is assumed at port 1080. - --To specify proxy on a unix domain socket, use localhost for host, e.g. -+To specify proxy on a Unix domain socket, use localhost for host, e.g. - `socks5h://localhost/path/to/socket.sock` - - This option overrides any previous use of --proxy, as they are mutually -diff --git a/docs/cmdline-opts/socks5.md b/docs/cmdline-opts/socks5.md -index f17dfeb71..4ea660d62 100644 ---- a/docs/cmdline-opts/socks5.md -+++ b/docs/cmdline-opts/socks5.md -@@ -19,7 +19,7 @@ Example: - Use the specified SOCKS5 proxy - but resolve the hostname locally. If the - port number is not specified, it is assumed at port 1080. - --To specify proxy on a unix domain socket, use localhost for host, e.g. -+To specify proxy on a Unix domain socket, use localhost for host, e.g. - `socks5://localhost/path/to/socket.sock` - - This option overrides any previous use of --proxy, as they are mutually -@@ -33,4 +33,4 @@ used with an HTTP/HTTPS proxy (added in 7.52.0). In such a case, curl first - connects to the SOCKS proxy and then connects (through SOCKS) to the HTTP or - HTTPS proxy. - --This option (as well as --socks4) does not work with IPV6, FTPS or LDAP. -+This option does not work with FTPS or LDAP. -diff --git a/docs/cmdline-opts/speed-time.md b/docs/cmdline-opts/speed-time.md -index ef8759ee5..f27702bec 100644 ---- a/docs/cmdline-opts/speed-time.md -+++ b/docs/cmdline-opts/speed-time.md -@@ -5,7 +5,7 @@ Long: speed-time - Short: y - Arg: - Help: Trigger 'speed-limit' abort after this time --Category: connection -+Category: connection timeout - Added: 4.7 - Multi: single - See-also: -diff --git a/docs/cmdline-opts/ssl-allow-beast.md b/docs/cmdline-opts/ssl-allow-beast.md -index 29f2b450c..f9933b77a 100644 ---- a/docs/cmdline-opts/ssl-allow-beast.md -+++ b/docs/cmdline-opts/ssl-allow-beast.md -@@ -16,9 +16,12 @@ Example: - - # `--ssl-allow-beast` - --Do not work around a security flaw in the SSL3 and TLS1.0 protocols known as --BEAST. If this option is not used, the SSL layer may use workarounds known to --cause interoperability problems with some older SSL implementations. -+Do not work around a security flaw in the TLS1.0 protocol known as BEAST. If -+this option is not used, the TLS layer may use workarounds known to cause -+interoperability problems with some older server implementations. - --**WARNING**: this option loosens the SSL security, and by using this flag you -+This option only changes how curl does TLS 1.0 and has no effect on later TLS -+versions. -+ -+**WARNING**: this option loosens the TLS security, and by using this flag you - ask for exactly that. -diff --git a/docs/cmdline-opts/ssl-reqd.md b/docs/cmdline-opts/ssl-reqd.md -index eeabc0645..f21c145f5 100644 ---- a/docs/cmdline-opts/ssl-reqd.md -+++ b/docs/cmdline-opts/ssl-reqd.md -@@ -5,7 +5,7 @@ Long: ssl-reqd - Help: Require SSL/TLS - Protocols: FTP IMAP POP3 SMTP LDAP - Added: 7.20.0 --Category: tls -+Category: tls imap pop3 smtp ldap - Multi: boolean - See-also: - - ssl -@@ -16,7 +16,8 @@ Example: - - # `--ssl-reqd` - --Require SSL/TLS for the connection. Terminates the connection if the transfer -+Require SSL/TLS for the connection - often referred to as STARTTLS or STLS -+because of the involved commands. Terminates the connection if the transfer - cannot be upgraded to use SSL/TLS. - - This option is handled in LDAP (added in 7.81.0). It is fully supported by the -diff --git a/docs/cmdline-opts/ssl.md b/docs/cmdline-opts/ssl.md -index 73fa96ad6..0c0f28172 100644 ---- a/docs/cmdline-opts/ssl.md -+++ b/docs/cmdline-opts/ssl.md -@@ -5,7 +5,7 @@ Long: ssl - Help: Try enabling TLS - Protocols: FTP IMAP POP3 SMTP LDAP - Added: 7.20.0 --Category: tls -+Category: tls imap pop3 smtp ldap - Multi: boolean - See-also: - - ssl-reqd -@@ -20,9 +20,10 @@ Example: - Warning: this is considered an insecure option. Consider using --ssl-reqd - instead to be sure curl upgrades to a secure connection. - --Try to use SSL/TLS for the connection. Reverts to a non-secure connection if --the server does not support SSL/TLS. See also --ftp-ssl-control and --ssl-reqd --for different levels of encryption required. -+Try to use SSL/TLS for the connection - often referred to as STARTTLS or STLS -+because of the involved commands. Reverts to a non-secure connection if the -+server does not support SSL/TLS. See also --ftp-ssl-control and --ssl-reqd for -+different levels of encryption required. - - This option is handled in LDAP (added in 7.81.0). It is fully supported by the - OpenLDAP backend and ignored by the generic ldap backend. -diff --git a/docs/cmdline-opts/sslv2.md b/docs/cmdline-opts/sslv2.md -index 3bd36f02c..ea92a2cb4 100644 ---- a/docs/cmdline-opts/sslv2.md -+++ b/docs/cmdline-opts/sslv2.md -@@ -9,7 +9,7 @@ Added: 5.9 - Mutexed: sslv3 tlsv1 tlsv1.1 tlsv1.2 - Requires: TLS - Help: SSLv2 --Category: tls -+Category: deprecated - Multi: mutex - See-also: - - http1.1 -diff --git a/docs/cmdline-opts/sslv3.md b/docs/cmdline-opts/sslv3.md -index 32d4c1206..f022124e1 100644 ---- a/docs/cmdline-opts/sslv3.md -+++ b/docs/cmdline-opts/sslv3.md -@@ -9,7 +9,7 @@ Added: 5.9 - Mutexed: sslv2 tlsv1 tlsv1.1 tlsv1.2 - Requires: TLS - Help: SSLv3 --Category: tls -+Category: deprecated - Multi: mutex - See-also: - - http1.1 -diff --git a/docs/cmdline-opts/stderr.md b/docs/cmdline-opts/stderr.md -index bb42497de..7030e557b 100644 ---- a/docs/cmdline-opts/stderr.md -+++ b/docs/cmdline-opts/stderr.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: stderr - Arg: - Help: Where to redirect stderr --Category: verbose -+Category: verbose global - Added: 6.2 - Multi: single - Scope: global -diff --git a/docs/cmdline-opts/styled-output.md b/docs/cmdline-opts/styled-output.md -index bb324532b..8193896c5 100644 ---- a/docs/cmdline-opts/styled-output.md -+++ b/docs/cmdline-opts/styled-output.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: styled-output - Help: Enable styled output for HTTP headers - Added: 7.61.0 --Category: verbose -+Category: verbose global - Multi: boolean - Scope: global - See-also: -diff --git a/docs/cmdline-opts/suppress-connect-headers.md b/docs/cmdline-opts/suppress-connect-headers.md -index 9e2eefea4..e9e32c0ab 100644 ---- a/docs/cmdline-opts/suppress-connect-headers.md -+++ b/docs/cmdline-opts/suppress-connect-headers.md -@@ -8,15 +8,16 @@ Added: 7.54.0 - Multi: boolean - See-also: - - dump-header -- - include -+ - show-headers - - proxytunnel - Example: -- - --suppress-connect-headers --include -x proxy $URL -+ - --suppress-connect-headers --show-headers -x proxy $URL - --- - - # `--suppress-connect-headers` - - When --proxytunnel is used and a CONNECT request is made do not output proxy --CONNECT response headers. This option is meant to be used with --dump-header or ----include which are used to show protocol headers in the output. It has no --effect on debug options such as --verbose or --trace, or any statistics. -+CONNECT response headers. This option is meant to be used with --dump-header -+or --show-headers which are used to show protocol headers in the output. It -+has no effect on debug options such as --verbose or --trace, or any -+statistics. -diff --git a/docs/cmdline-opts/tls-earlydata.md b/docs/cmdline-opts/tls-earlydata.md -new file mode 100644 -index 000000000..8482f809e ---- /dev/null -+++ b/docs/cmdline-opts/tls-earlydata.md -@@ -0,0 +1,41 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: tls-earlydata -+Help: Allow use of TLSv1.3 early data (0RTT) -+Protocols: TLS -+Added: 8.11.0 -+Category: tls -+Multi: boolean -+See-also: -+ - tlsv1.3 -+ - tls-max -+Example: -+ - --tls-earlydata $URL -+--- -+ -+# `--tls-earlydata` -+ -+Enable the use of TLSv1.3 early data, also known as '0RTT' where possible. -+This has security implications for the requests sent that way. -+ -+This option is used when curl is built to use GnuTLS. -+ -+If a server supports this TLSv1.3 feature, and to what extent, is announced -+as part of the TLS "session" sent back to curl. Until curl has seen such -+a session in a previous request, early data cannot be used. -+ -+When a new connection is initiated with a known TLSv1.3 session, and that -+session announced early data support, the first request on this connection is -+sent *before* the TLS handshake is complete. While the early data is also -+encrypted, it is not protected against replays. An attacker can send -+your early data to the server again and the server would accept it. -+ -+If your request contacts a public server and only retrieves a file, there -+may be no harm in that. If the first request orders a refrigerator -+for you, it is probably not a good idea to use early data for it. curl -+cannot deduce what the security implications of your requests actually -+are and make this decision for you. -+ -+**WARNING**: this option has security implications. See above for more -+details. -diff --git a/docs/cmdline-opts/tls13-ciphers.md b/docs/cmdline-opts/tls13-ciphers.md -index 55145aacf..43220af4d 100644 ---- a/docs/cmdline-opts/tls13-ciphers.md -+++ b/docs/cmdline-opts/tls13-ciphers.md -@@ -10,8 +10,8 @@ Added: 7.61.0 - Multi: single - See-also: - - ciphers -- - curves - - proxy-tls13-ciphers -+ - curves - Example: - - --tls13-ciphers TLS_AES_128_GCM_SHA256 $URL - --- -@@ -24,6 +24,8 @@ cipher suite details on this URL: - - https://curl.se/docs/ssl-ciphers.html - --This option is currently used only when curl is built to use OpenSSL 1.1.1 or --later, or Schannel. If you are using a different SSL backend you can try --setting TLS 1.3 cipher suites by using the --ciphers option. -+This option is used when curl is built to use OpenSSL 1.1.1 or later, -+Schannel, wolfSSL, or mbedTLS 3.6.0 or later. -+ -+Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites were set -+by using the --ciphers option. -diff --git a/docs/cmdline-opts/tlspassword.md b/docs/cmdline-opts/tlspassword.md -index 4b1817994..6a1bb23a1 100644 ---- a/docs/cmdline-opts/tlspassword.md -+++ b/docs/cmdline-opts/tlspassword.md -@@ -16,7 +16,7 @@ Example: - - # `--tlspassword` - --Set password for use with the TLS authentication method specified with ----tlsauthtype. Requires that --tlsuser also be set. -+Set password to use with the TLS authentication method specified with -+--tlsauthtype. Requires that --tlsuser is set. - - This option does not work with TLS 1.3. -diff --git a/docs/cmdline-opts/trace-ascii.md b/docs/cmdline-opts/trace-ascii.md -index 34f4d9f41..f46f0a6f3 100644 ---- a/docs/cmdline-opts/trace-ascii.md -+++ b/docs/cmdline-opts/trace-ascii.md -@@ -5,7 +5,7 @@ Long: trace-ascii - Arg: - Help: Like --trace, but without hex output - Mutexed: trace verbose --Category: verbose -+Category: verbose global - Added: 7.9.7 - Multi: single - Scope: global -@@ -20,7 +20,7 @@ Example: - - Save a full trace dump of all incoming and outgoing data, including - descriptive information, in the given output file. Use `-` as filename to have --the output sent to stdout. -+the output sent to stdout. Use `%` as filename to send the output to stderr. - - This is similar to --trace, but leaves out the hex part and only shows the - ASCII part of the dump. It makes smaller output that might be easier to read -diff --git a/docs/cmdline-opts/trace-config.md b/docs/cmdline-opts/trace-config.md -index d7c7e0daa..2f095401d 100644 ---- a/docs/cmdline-opts/trace-config.md -+++ b/docs/cmdline-opts/trace-config.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: trace-config - Arg: - Help: Details to log in trace/verbose output --Category: verbose -+Category: verbose global - Added: 8.3.0 - Multi: append - Scope: global -diff --git a/docs/cmdline-opts/trace-ids.md b/docs/cmdline-opts/trace-ids.md -index bf54ecb34..dc7d61e7f 100644 ---- a/docs/cmdline-opts/trace-ids.md -+++ b/docs/cmdline-opts/trace-ids.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: trace-ids - Help: Transfer + connection ids in verbose output - Added: 8.2.0 --Category: verbose -+Category: verbose global - Multi: boolean - Scope: global - See-also: -diff --git a/docs/cmdline-opts/trace-time.md b/docs/cmdline-opts/trace-time.md -index 79206ba9e..d3e0f47c1 100644 ---- a/docs/cmdline-opts/trace-time.md -+++ b/docs/cmdline-opts/trace-time.md -@@ -4,7 +4,7 @@ SPDX-License-Identifier: curl - Long: trace-time - Help: Add time stamps to trace/verbose output - Added: 7.14.0 --Category: verbose -+Category: verbose global - Multi: boolean - Scope: global - See-also: -diff --git a/docs/cmdline-opts/trace.md b/docs/cmdline-opts/trace.md -index f6e3e4b55..875e756fd 100644 ---- a/docs/cmdline-opts/trace.md -+++ b/docs/cmdline-opts/trace.md -@@ -5,7 +5,7 @@ Long: trace - Arg: - Help: Write a debug trace to FILE - Mutexed: verbose trace-ascii --Category: verbose -+Category: verbose global - Added: 7.9.7 - Multi: single - Scope: global -@@ -21,8 +21,8 @@ Example: - # `--trace` - - Save a full trace dump of all incoming and outgoing data, including --descriptive information, in the given output file. Use "-" as filename to have --the output sent to stdout. Use "%" as filename to have the output sent to -+descriptive information, in the given output file. Use `-` as filename to have -+the output sent to stdout. Use `%` as filename to have the output sent to - stderr. - - Note that verbose output of curl activities and network traffic might contain -diff --git a/docs/cmdline-opts/upload-file.md b/docs/cmdline-opts/upload-file.md -index 74e7af302..7e9ffbf1e 100644 ---- a/docs/cmdline-opts/upload-file.md -+++ b/docs/cmdline-opts/upload-file.md -@@ -7,7 +7,7 @@ Arg: - Help: Transfer local FILE to destination - Category: important upload - Added: 4.0 --Multi: append -+Multi: per-URL - See-also: - - get - - head -@@ -17,6 +17,7 @@ Example: - - -T file $URL - - -T "img[1-1000].png" ftp://ftp.example.com/ - - --upload-file "{file1,file2}" $URL -+ - -T file -T file2 $URL $URL - --- - - # `--upload-file` -diff --git a/docs/cmdline-opts/url.md b/docs/cmdline-opts/url.md -index c3680b641..d19c73ecb 100644 ---- a/docs/cmdline-opts/url.md -+++ b/docs/cmdline-opts/url.md -@@ -16,17 +16,19 @@ Example: - - # `--url` - --Specify a URL to fetch. -+Specify a URL to fetch or send data to. - --If the given URL is missing a scheme name (such as `http://` or `ftp://` etc) --then curl makes a guess based on the host. If the outermost subdomain name --matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that protocol is used, --otherwise HTTP is used. Guessing can be avoided by providing a full URL --including the scheme, or disabled by setting a default protocol (added in --7.45.0), see --proto-default for details. -+If the given URL is missing a scheme (such as `http://` or `ftp://` etc) curl -+guesses which scheme to use based on the hostname. If the outermost subdomain -+name matches DICT, FTP, IMAP, LDAP, POP3 or SMTP case insensitively, then that -+protocol is used, otherwise it assumes HTTP. Scheme guessing can be avoided by -+providing a full URL including the scheme, or disabled by setting a default -+protocol, see --proto-default for details. - --To control where this URL is written, use the --output or the --remote-name --options. -+To control where the contents of a retrieved URL is written instead of the -+default stdout, use the --output or the --remote-name options. When retrieving -+multiple URLs in a single invoke, each provided URL needs its own dedicated -+destination option unless --remote-name-all is used. - --**WARNING**: On Windows, particular `file://` accesses can be converted to --network accesses by the operating system. Beware! -+On Windows, `file://` accesses can be converted to network accesses by the -+operating system. -diff --git a/docs/cmdline-opts/use-ascii.md b/docs/cmdline-opts/use-ascii.md -index 3586aa212..30cc860b0 100644 ---- a/docs/cmdline-opts/use-ascii.md -+++ b/docs/cmdline-opts/use-ascii.md -@@ -5,7 +5,7 @@ Short: B - Long: use-ascii - Help: Use ASCII/text transfer - Protocols: FTP LDAP --Category: misc -+Category: ftp output ldap - Added: 5.0 - Multi: boolean - See-also: -@@ -19,4 +19,4 @@ Example: - - Enable ASCII transfer mode. For FTP, this can also be enforced by using a URL - that ends with `;type=A`. This option causes data sent to stdout to be in text --mode for win32 systems. -+mode for Win32 systems. -diff --git a/docs/cmdline-opts/variable.md b/docs/cmdline-opts/variable.md -index 9da1d3fee..9fe057236 100644 ---- a/docs/cmdline-opts/variable.md -+++ b/docs/cmdline-opts/variable.md -@@ -10,7 +10,7 @@ Multi: append - See-also: - - config - Example: -- - --variable name=smith $URL -+ - --variable name=smith --expand-url "$URL/{{name}}" - --- - - # `--variable` -diff --git a/docs/cmdline-opts/verbose.md b/docs/cmdline-opts/verbose.md -index 53096c546..d29e23a7b 100644 ---- a/docs/cmdline-opts/verbose.md -+++ b/docs/cmdline-opts/verbose.md -@@ -5,12 +5,12 @@ Short: v - Long: verbose - Mutexed: trace trace-ascii - Help: Make the operation more talkative --Category: important verbose -+Category: important verbose global - Added: 4.0 - Multi: boolean - Scope: global - See-also: -- - include -+ - show-headers - - silent - - trace - - trace-ascii -@@ -25,11 +25,30 @@ what's going on under the hood. A line starting with \> means header data sent - by curl, \< means header data received by curl that is hidden in normal cases, - and a line starting with * means additional info provided by curl. - --If you only want HTTP headers in the output, --include or --dump-header might --be more suitable options. -+If you only want HTTP headers in the output, --show-headers or --dump-header -+might be more suitable options. - --If you think this option still does not give you enough details, consider using ----trace or --trace-ascii instead. -+Since curl 8.10, mentioning this option several times in the same argument -+increases the level of the trace output. However, as before, a single -+--verbose or --no-verbose reverts any additions by previous `-vv` again. This -+means that `-vv -v` is equivalent to a single -v. This avoids unwanted -+verbosity when the option is mentioned in the command line *and* curl config -+files. -+ -+Using it twice, e.g. `-vv`, outputs time (--trace-time) and transfer ids -+(--trace-ids), as well as enable tracing for all protocols (--trace-config -+protocol). -+ -+Adding a third verbose outputs transfer content (--trace-ascii %) and enable -+tracing of more components (--trace-config read,write,ssl). -+ -+A forth time adds tracing of all network components. (--trace-config network). -+ -+Any addition of the verbose option after that has no effect. -+ -+If you think this option does not give you the right details, consider using -+--trace or --trace-ascii instead. Or use it only once and use --trace-config -+to trace the specific components you wish to see. - - Note that verbose output of curl activities and network traffic might contain - sensitive data, including usernames, credentials or secret data content. Be -diff --git a/docs/cmdline-opts/version.md b/docs/cmdline-opts/version.md -index 0fe8d7419..0597f84a2 100644 ---- a/docs/cmdline-opts/version.md -+++ b/docs/cmdline-opts/version.md -@@ -44,7 +44,10 @@ curl was built with support for character set conversions (like EBCDIC) - - ## `Debug` - This curl uses a libcurl built with Debug. This enables more error-tracking --and memory debugging etc. For curl-developers only! -+and memory debugging etc. For curl-developers only. -+ -+## `ECH` -+ECH support is present. - - ## `gsasl` - The built-in SASL authentication includes extensions to support SCRAM because -@@ -89,6 +92,7 @@ NTLM authentication is supported. - - ## `NTLM_WB` - NTLM delegation to winbind helper is supported. -+This feature was removed from curl in 8.8.0. - - ## `PSL` - PSL is short for Public Suffix List and means that this curl has been built -diff --git a/docs/cmdline-opts/vlan-priority.md b/docs/cmdline-opts/vlan-priority.md -new file mode 100644 -index 000000000..34dc8ce06 ---- /dev/null -+++ b/docs/cmdline-opts/vlan-priority.md -@@ -0,0 +1,23 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: vlan-priority -+Arg: -+Help: Set VLAN priority -+Added: 8.9.0 -+Category: connection -+Protocols: All -+Multi: single -+See-also: -+ - ip-tos -+Example: -+ - --vlan-priority 4 $URL -+--- -+ -+# `--vlan-priority` -+ -+Set VLAN priority as defined in IEEE 802.1Q. -+ -+This field is set on Ethernet level, and only works within a local network. -+ -+The valid range for \ is 0 to 7. -diff --git a/docs/cmdline-opts/write-out.md b/docs/cmdline-opts/write-out.md -index bb1422c99..3f8af2b5e 100644 ---- a/docs/cmdline-opts/write-out.md -+++ b/docs/cmdline-opts/write-out.md -@@ -63,6 +63,11 @@ The variables available are: - Output the certificate chain with details. Supported only by the OpenSSL, - GnuTLS, Schannel and Secure Transport backends. (Added in 7.88.0) - -+## `conn_id` -+The connection identifier last used by the transfer. The connection id is -+unique number among all connections using the same connection cache. -+(Added in 8.2.0) -+ - ## `content_type` - The Content-Type of the requested document, if there was any. - -@@ -75,8 +80,8 @@ The numerical exit code of the transfer. (Added in 7.75.0) - ## `filename_effective` - The ultimate filename that curl writes out to. This is only meaningful if curl - is told to write to a file with the --remote-name or --output option. It is --most useful in combination with the --remote-header-name option. (Added in --7.26.0) -+most useful in combination with the --remote-header-name option. -+(Added in 7.26.0) - - ## `ftp_entry_path` - The initial path curl ended up in when logging on to the remote FTP -@@ -130,6 +135,10 @@ redirect). Note that the status line IS NOT a header. (Added in 7.73.0) - ## `num_redirects` - Number of redirects that were followed in the request. (Added in 7.12.3) - -+## `num_retries` -+Number of retries actually performed when `--retry` has been used. -+(Added in 8.9.0) -+ - ## `onerror` - The rest of the output is only shown if the transfer returned a non-zero error. - (Added in 7.75.0) -@@ -212,6 +221,10 @@ remote host (or proxy) was completed. - The time, in seconds, it took from the start until the name resolving was - completed. - -+## `time_posttransfer` -+The time it took from the start until the last byte is sent by libcurl. -+In microseconds. (Added in 8.10.0) -+ - ## `time_pretransfer` - The time, in seconds, it took from the start until the file transfer was just - about to begin. This includes all pre-transfer commands and negotiations that -@@ -305,3 +318,9 @@ same index number as the origin globbed URL. (Added in 7.75.0) - ## `url_effective` - The URL that was fetched last. This is most meaningful if you have told curl - to follow location: headers. -+ -+## `xfer_id` -+The numerical identifier of the last transfer done. -1 if no transfer has been -+started yet for the handle. The transfer id is unique among all transfers -+performed using the same connection cache. -+(Added in 8.2.0) -diff --git a/docs/cmdline-opts/xattr.md b/docs/cmdline-opts/xattr.md -index bfa74cf5a..0c3bb753a 100644 ---- a/docs/cmdline-opts/xattr.md -+++ b/docs/cmdline-opts/xattr.md -@@ -3,7 +3,7 @@ c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl - Long: xattr - Help: Store metadata in extended file attributes --Category: misc -+Category: output - Added: 7.21.3 - Multi: boolean - See-also: -@@ -17,7 +17,7 @@ Example: - # `--xattr` - - When saving output to a file, tell curl to store file metadata in extended --file attributes. Currently, the URL is stored in the `xdg.origin.url` --attribute and, for HTTP, the content type is stored in the `mime_type` --attribute. If the file system does not support extended attributes, a warning --is issued. -+file attributes. Currently, `curl` is stored in the `creator` attribute, -+the URL is stored in the `xdg.origin.url` attribute and, for HTTP, the content -+type is stored in the `mime_type` attribute. If the file system does not -+support extended attributes, a warning is issued. -diff --git a/docs/curl-config.md b/docs/curl-config.md -index d82725082..4dfaab6ad 100644 ---- a/docs/curl-config.md -+++ b/docs/curl-config.md -@@ -6,6 +6,7 @@ Section: 1 - Source: curl-config - See-also: - - curl (1) -+Added-in: 7.7.2 - --- - - # NAME -diff --git a/docs/examples/.gitignore b/docs/examples/.gitignore -index f9a2c7797..68f96939a 100644 ---- a/docs/examples/.gitignore -+++ b/docs/examples/.gitignore -@@ -3,12 +3,15 @@ - # SPDX-License-Identifier: curl - - 10-at-a-time -+address-scope - altsvc - anyauthput - certinfo - chkspeed -+connect-to - cookie_interface - debug -+default-scheme - externalsocket - fileupload - fopen -@@ -20,10 +23,13 @@ ftpsget - ftpupload - ftpuploadfrommem - ftpuploadresume --getreferrer - getinfo - getinmemory - getredirect -+getreferrer -+headerapi -+hsts-preload -+http-options - http-post - http2-download - http2-pushinmemory -@@ -50,6 +56,11 @@ imap-search - imap-ssl - imap-store - imap-tls -+interface -+ipv6 -+keepalive -+localport -+maxconnects - multi-app - multi-debugcallback - multi-double -@@ -58,6 +69,8 @@ multi-legacy - multi-poll - multi-post - multi-single -+netrc -+new-gitignore - parseurl - persistent - pop3-authzid -@@ -76,8 +89,11 @@ postinmemory - postit2 - postit2-formadd - progressfunc -+protofeats -+range - resolve - rtsp -+rtsp-options - sendrecv - sepheaders - sftpget -@@ -95,7 +111,10 @@ smtp-ssl - smtp-tls - smtp-vrfy - sslbackend --urlapi -+unixsocket - url2file -+urlapi - usercertinmem -+websocket -+websocket-cb - xmlstream -diff --git a/docs/examples/10-at-a-time.c b/docs/examples/10-at-a-time.c -index a622410fd..38a0f24ac 100644 ---- a/docs/examples/10-at-a-time.c -+++ b/docs/examples/10-at-a-time.c -@@ -26,12 +26,8 @@ - * - */ - --#include - #include - #include --#ifndef _WIN32 --# include --#endif - #include - - static const char *urls[] = { -@@ -127,7 +123,8 @@ int main(void) - int still_alive = 1; - curl_multi_perform(cm, &still_alive); - -- while((msg = curl_multi_info_read(cm, &msgs_left))) { -+ /* !checksrc! disable EQUALSNULL 1 */ -+ while((msg = curl_multi_info_read(cm, &msgs_left)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - char *url; - CURL *e = msg->easy_handle; -diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt -new file mode 100644 -index 000000000..21c427d12 ---- /dev/null -+++ b/docs/examples/CMakeLists.txt -@@ -0,0 +1,43 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+ -+add_custom_target(curl-examples) -+ -+# Get 'check_PROGRAMS' variable -+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+ -+foreach(_target IN LISTS check_PROGRAMS) -+ set(_target_name "curl-example-${_target}") -+ add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c") -+ add_dependencies(curl-examples ${_target_name}) -+ target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_LIBS}) -+ target_compile_definitions(${_target_name} PRIVATE "CURL_NO_OLDIES") -+ if(LIB_SELECTED STREQUAL LIB_STATIC AND WIN32) -+ set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB") -+ endif() -+ set_target_properties(${_target_name} PROPERTIES -+ OUTPUT_NAME "${_target}" UNITY_BUILD OFF -+ PROJECT_LABEL "Example ${_target}") -+endforeach() -diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am -index 80ccc5925..e5ff9ffdc 100644 ---- a/docs/examples/Makefile.am -+++ b/docs/examples/Makefile.am -@@ -24,7 +24,7 @@ - - AUTOMAKE_OPTIONS = foreign nostdinc - --EXTRA_DIST = README.md Makefile.example Makefile.inc Makefile.mk \ -+EXTRA_DIST = README.md Makefile.example Makefile.mk CMakeLists.txt \ - $(COMPLICATED_EXAMPLES) .checksrc - - # Specify our include paths here, and do it relative to $(top_srcdir) and -@@ -34,8 +34,7 @@ EXTRA_DIST = README.md Makefile.example Makefile.inc Makefile.mk \ - # - # $(top_srcdir)/include is for libcurl's external include files - --AM_CPPFLAGS = -I$(top_srcdir)/include \ -- -DCURL_DISABLE_DEPRECATION -+AM_CPPFLAGS = -I$(top_srcdir)/include - - LIBDIR = $(top_builddir)/lib - -@@ -50,11 +49,7 @@ endif - LIBS = $(BLANK_AT_MAKETIME) - - # Dependencies --if USE_EXPLICIT_LIB_DEPS --LDADD = $(LIBDIR)/libcurl.la @LIBCURL_LIBS@ --else --LDADD = $(LIBDIR)/libcurl.la --endif -+LDADD = $(LIBDIR)/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@ - - # This might hold -Werror - CFLAGS += @CURL_CFLAG_EXTRAS@ -diff --git a/docs/examples/Makefile.example b/docs/examples/Makefile.example -index b10cdecf5..cfb59c94e 100644 ---- a/docs/examples/Makefile.example -+++ b/docs/examples/Makefile.example -@@ -36,7 +36,7 @@ CFLAGS = -c -g - - # This should point to a directory that holds libcurl, if it is not - # in the system's standard lib dir --# We also set a -L to include the directory where we have the openssl -+# We also set a -L to include the directory where we have the OpenSSL - # libraries - LDFLAGS = -L/home/dast/lib -L/usr/local/ssl/lib - -diff --git a/docs/examples/README.md b/docs/examples/README.md -index 3f95f03c0..a6a31c938 100644 ---- a/docs/examples/README.md -+++ b/docs/examples/README.md -@@ -21,12 +21,12 @@ first. - - Most examples should build fine using a command line like this: - -- `curl-config --cc --cflags --libs` -o example example.c -+ `curl-config --cc --cflags --libs` -o example-my example.c - - Some compilers do not like having the arguments in this order but instead - want you do reorganize them like: - -- `curl-config --cc` -o example example.c `curl-config --cflags --libs` -+ `curl-config --cc` -o example-my example.c `curl-config --cflags --libs` - - **Please** do not use the `curl.se` site as a test target for your libcurl - applications/experiments. Even if some of the examples use that site as a URL -diff --git a/docs/examples/address-scope.c b/docs/examples/address-scope.c -index 5650fdb23..a4ae26539 100644 ---- a/docs/examples/address-scope.c -+++ b/docs/examples/address-scope.c -@@ -44,7 +44,7 @@ int main(void) - long my_scope_id; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); - -- my_scope_id = if_nametoindex("eth0"); -+ my_scope_id = (long)if_nametoindex("eth0"); - curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, my_scope_id); - - /* Perform the request, res gets the return code */ -diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c -index 269e29cf5..3bbc056c0 100644 ---- a/docs/examples/anyauthput.c -+++ b/docs/examples/anyauthput.c -@@ -100,7 +100,7 @@ int main(int argc, char **argv) - fp = fopen(file, "rb"); - fstat(FILENO(fp), &file_info); - -- /* In windows, this inits the winsock stuff */ -+ /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); - - /* get a curl handle */ -diff --git a/docs/examples/chkspeed.c b/docs/examples/chkspeed.c -index a8d95666c..687b264b9 100644 ---- a/docs/examples/chkspeed.c -+++ b/docs/examples/chkspeed.c -@@ -180,31 +180,31 @@ int main(int argc, char *argv[]) - - /* check for bytes downloaded */ - res = curl_easy_getinfo(curl_handle, CURLINFO_SIZE_DOWNLOAD_T, &val); -- if((CURLE_OK == res) && (val>0)) -+ if((CURLE_OK == res) && (val > 0)) - printf("Data downloaded: %lu bytes.\n", (unsigned long)val); - - /* check for total download time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_TOTAL_TIME_T, &val); -- if((CURLE_OK == res) && (val>0)) -+ if((CURLE_OK == res) && (val > 0)) - printf("Total download time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); - - /* check for average download speed */ - res = curl_easy_getinfo(curl_handle, CURLINFO_SPEED_DOWNLOAD_T, &val); -- if((CURLE_OK == res) && (val>0)) -+ if((CURLE_OK == res) && (val > 0)) - printf("Average download speed: %lu kbyte/sec.\n", - (unsigned long)(val / 1024)); - - if(prtall) { - /* check for name resolution time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_NAMELOOKUP_TIME_T, &val); -- if((CURLE_OK == res) && (val>0)) -+ if((CURLE_OK == res) && (val > 0)) - printf("Name lookup time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); - - /* check for connect time */ - res = curl_easy_getinfo(curl_handle, CURLINFO_CONNECT_TIME_T, &val); -- if((CURLE_OK == res) && (val>0)) -+ if((CURLE_OK == res) && (val > 0)) - printf("Connect time: %lu.%06lu sec.\n", - (unsigned long)(val / 1000000), (unsigned long)(val % 1000000)); - } -diff --git a/docs/examples/cookie_interface.c b/docs/examples/cookie_interface.c -index 0cc47cff7..396aeca97 100644 ---- a/docs/examples/cookie_interface.c -+++ b/docs/examples/cookie_interface.c -@@ -29,10 +29,10 @@ - #include - #include - #include --#include - #include - - #include -+#include - - static void - print_cookies(CURL *curl) -@@ -91,14 +91,11 @@ main(void) - - printf("-----------------------------------------------\n" - "Setting a cookie \"PREF\" via cookie interface:\n"); --#ifdef _WIN32 --#define snprintf _snprintf --#endif - /* Netscape format cookie */ -- snprintf(nline, sizeof(nline), "%s\t%s\t%s\t%s\t%.0f\t%s\t%s", -- ".example.com", "TRUE", "/", "FALSE", -- difftime(time(NULL) + 31337, (time_t)0), -- "PREF", "hello example, i like you!"); -+ curl_msnprintf(nline, sizeof(nline), "%s\t%s\t%s\t%s\t%.0f\t%s\t%s", -+ ".example.com", "TRUE", "/", "FALSE", -+ difftime(time(NULL) + 31337, (time_t)0), -+ "PREF", "hello example, i like you!"); - res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); - if(res != CURLE_OK) { - fprintf(stderr, "Curl curl_easy_setopt failed: %s\n", -@@ -111,7 +108,7 @@ main(void) - modified, likely not what you intended. For more information refer to - the CURLOPT_COOKIELIST documentation. - */ -- snprintf(nline, sizeof(nline), -+ curl_msnprintf(nline, sizeof(nline), - "Set-Cookie: OLD_PREF=3d141414bf4209321; " - "expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.example.com"); - res = curl_easy_setopt(curl, CURLOPT_COOKIELIST, nline); -diff --git a/docs/examples/debug.c b/docs/examples/debug.c -index 68d93039e..2bd8b971a 100644 ---- a/docs/examples/debug.c -+++ b/docs/examples/debug.c -@@ -49,7 +49,7 @@ void dump(const char *text, - fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n", - text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -128,7 +128,7 @@ int main(void) - CURLcode res; - struct data config; - -- config.trace_ascii = 1; /* enable ascii tracing */ -+ config.trace_ascii = 1; /* enable ASCII tracing */ - - curl = curl_easy_init(); - if(curl) { -diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c -index 0c8a26924..8edcd2015 100644 ---- a/docs/examples/ephiperfifo.c -+++ b/docs/examples/ephiperfifo.c -@@ -33,7 +33,7 @@ - * - * Written by Jeff Pohlmeyer, converted to use epoll by Josh Bialkowski - --Requires a linux system with epoll -+Requires a Linux system with epoll - - When running, the program creates the named pipe "hiper.fifo" - -diff --git a/docs/examples/externalsocket.c b/docs/examples/externalsocket.c -index 21e9a9c47..010654298 100644 ---- a/docs/examples/externalsocket.c -+++ b/docs/examples/externalsocket.c -@@ -25,19 +25,24 @@ - * Pass in a custom socket for libcurl to use. - * - */ -+#ifdef _WIN32 -+#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -+#define _WINSOCK_DEPRECATED_NO_WARNINGS /* for inet_addr() */ -+#endif -+#endif -+ - #include - #include - #include - #include - - #ifdef _WIN32 --#include - #define close closesocket - #else - #include /* socket types */ - #include /* socket definitions */ - #include --#include /* inet (3) functions */ -+#include /* inet (3) functions */ - #include /* misc. Unix functions */ - #endif - -diff --git a/docs/examples/ftp-wildcard.c b/docs/examples/ftp-wildcard.c -index 8a1b3c88f..53fb76e37 100644 ---- a/docs/examples/ftp-wildcard.c -+++ b/docs/examples/ftp-wildcard.c -@@ -50,9 +50,9 @@ int main(int argc, char **argv) - struct callback_data data = { 0 }; - - /* global initialization */ -- int rc = curl_global_init(CURL_GLOBAL_ALL); -+ CURLcode rc = curl_global_init(CURL_GLOBAL_ALL); - if(rc) -- return rc; -+ return (int)rc; - - /* initialization of easy handle */ - handle = curl_easy_init(); -@@ -90,7 +90,7 @@ int main(int argc, char **argv) - - curl_easy_cleanup(handle); - curl_global_cleanup(); -- return rc; -+ return (int)rc; - } - - static long file_is_coming(struct curl_fileinfo *finfo, -diff --git a/docs/examples/ftpgetinfo.c b/docs/examples/ftpgetinfo.c -index be24fa71e..485b26bdd 100644 ---- a/docs/examples/ftpgetinfo.c -+++ b/docs/examples/ftpgetinfo.c -@@ -74,7 +74,7 @@ int main(void) - } - res = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, - &filesize); -- if((CURLE_OK == res) && (filesize>0)) -+ if((CURLE_OK == res) && (filesize > 0)) - printf("filesize %s: %" CURL_FORMAT_CURL_OFF_T " bytes\n", - filename, filesize); - } -diff --git a/docs/examples/ftpgetresp.c b/docs/examples/ftpgetresp.c -index 33c26b380..256998d8c 100644 ---- a/docs/examples/ftpgetresp.c -+++ b/docs/examples/ftpgetresp.c -@@ -48,17 +48,17 @@ int main(void) - FILE *respfile; - - /* local filename to store the file as */ -- ftpfile = fopen(FTPBODY, "wb"); /* b is binary, needed on win32 */ -+ ftpfile = fopen(FTPBODY, "wb"); /* b is binary, needed on Windows */ - - /* local filename to store the FTP server's response lines in */ -- respfile = fopen(FTPHEADERS, "wb"); /* b is binary, needed on win32 */ -+ respfile = fopen(FTPHEADERS, "wb"); /* b is binary, needed on Windows */ - - curl = curl_easy_init(); - if(curl) { - /* Get a file listing from sunet */ - curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.example.com/"); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, ftpfile); -- /* If you intend to use this on windows with a libcurl DLL, you must use -+ /* If you intend to use this on Windows with a libcurl DLL, you must use - CURLOPT_WRITEFUNCTION as well */ - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, respfile); -diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c -index d43f09026..462202e6c 100644 ---- a/docs/examples/ftpupload.c -+++ b/docs/examples/ftpupload.c -@@ -90,7 +90,7 @@ int main(void) - /* get a FILE * of the same file */ - hd_src = fopen(LOCAL_FILE, "rb"); - -- /* In windows, this inits the winsock stuff */ -+ /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); - - /* get a curl handle */ -diff --git a/docs/examples/ftpuploadfrommem.c b/docs/examples/ftpuploadfrommem.c -index 699468d1c..253748686 100644 ---- a/docs/examples/ftpuploadfrommem.c -+++ b/docs/examples/ftpuploadfrommem.c -@@ -76,7 +76,7 @@ int main(void) - upload.readptr = data; - upload.sizeleft = strlen(data); - -- /* In windows, this inits the winsock stuff */ -+ /* In Windows, this inits the Winsock stuff */ - res = curl_global_init(CURL_GLOBAL_DEFAULT); - /* Check for errors */ - if(res != CURLE_OK) { -diff --git a/docs/examples/ghiper.c b/docs/examples/ghiper.c -index ec7174ff7..57047eddd 100644 ---- a/docs/examples/ghiper.c -+++ b/docs/examples/ghiper.c -@@ -311,7 +311,7 @@ static void new_conn(char *url, GlobalInfo *g) - curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, (long)SHOW_VERBOSE); - curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); - curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); -- curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, SHOW_PROGRESS?0L:1L); -+ curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, SHOW_PROGRESS ? 0L : 1L); - curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); - curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); - curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); -diff --git a/docs/examples/htmltidy.c b/docs/examples/htmltidy.c -index cc6f63e1c..498bb85bd 100644 ---- a/docs/examples/htmltidy.c -+++ b/docs/examples/htmltidy.c -@@ -56,8 +56,8 @@ void dumpNode(TidyDoc doc, TidyNode tnod, int indent) - /* walk the attribute list */ - for(attr = tidyAttrFirst(child); attr; attr = tidyAttrNext(attr) ) { - printf("%s", tidyAttrName(attr)); -- tidyAttrValue(attr)?printf("=\"%s\" ", -- tidyAttrValue(attr)):printf(" "); -+ tidyAttrValue(attr) ? printf("=\"%s\" ", -+ tidyAttrValue(attr)) : printf(" "); - } - printf(">\n"); - } -@@ -66,7 +66,7 @@ void dumpNode(TidyDoc doc, TidyNode tnod, int indent) - TidyBuffer buf; - tidyBufInit(&buf); - tidyNodeGetText(doc, child, &buf); -- printf("%*.*s\n", indent, indent, buf.bp?(char *)buf.bp:""); -+ printf("%*.*s\n", indent, indent, buf.bp ? (char *)buf.bp : ""); - tidyBufFree(&buf); - } - dumpNode(doc, child, indent + 4); /* recursive */ -diff --git a/docs/examples/http-post.c b/docs/examples/http-post.c -index 1ee9f69c0..901ee1e3f 100644 ---- a/docs/examples/http-post.c -+++ b/docs/examples/http-post.c -@@ -33,7 +33,7 @@ int main(void) - CURL *curl; - CURLcode res; - -- /* In windows, this inits the winsock stuff */ -+ /* In Windows, this inits the Winsock stuff */ - curl_global_init(CURL_GLOBAL_ALL); - - /* get a curl handle */ -diff --git a/docs/examples/http2-download.c b/docs/examples/http2-download.c -index c45a1c2d6..ff74efb8c 100644 ---- a/docs/examples/http2-download.c -+++ b/docs/examples/http2-download.c -@@ -30,10 +30,6 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - #include -@@ -69,7 +65,7 @@ void dump(const char *text, unsigned int num, unsigned char *ptr, size_t size, - fprintf(stderr, "%u %s, %lu bytes (0x%lx)\n", - num, text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -diff --git a/docs/examples/http2-pushinmemory.c b/docs/examples/http2-pushinmemory.c -index 74c64e0a6..53c368e01 100644 ---- a/docs/examples/http2-pushinmemory.c -+++ b/docs/examples/http2-pushinmemory.c -@@ -29,10 +29,6 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - -diff --git a/docs/examples/http2-serverpush.c b/docs/examples/http2-serverpush.c -index e830aa95d..e259e1497 100644 ---- a/docs/examples/http2-serverpush.c -+++ b/docs/examples/http2-serverpush.c -@@ -29,12 +29,9 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include -+#include - - #ifndef CURLPIPE_MULTIPLEX - #error "too old libcurl, cannot do HTTP/2 server push!" -@@ -56,7 +53,7 @@ void dump(const char *text, unsigned char *ptr, size_t size, - fprintf(stderr, "%s, %lu bytes (0x%lx)\n", - text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -176,7 +173,7 @@ static int server_push_callback(CURL *parent, - - (void)parent; /* we have no use for this */ - -- snprintf(filename, 128, "push%u", count++); -+ curl_msnprintf(filename, 128, "push%u", count++); - - /* here's a new stream, save it in a new file for each new push */ - out = fopen(filename, "wb"); -@@ -192,7 +189,7 @@ static int server_push_callback(CURL *parent, - fprintf(stderr, "**** push callback approves stream %u, got %lu headers!\n", - count, (unsigned long)num_headers); - -- for(i = 0; i - #include - --/* somewhat unix-specific */ -+/* somewhat Unix-specific */ -+#ifndef _MSC_VER - #include - #include -+#endif - - /* curl stuff */ - #include -@@ -49,6 +51,27 @@ - - #define NUM_HANDLES 1000 - -+#ifdef _MSC_VER -+#define gettimeofday(a, b) my_gettimeofday((a), (b)) -+static -+int my_gettimeofday(struct timeval *tp, void *tzp) -+{ -+ (void)tzp; -+ if(tp) { -+ /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */ -+ #define _WIN32_FT_OFFSET (116444736000000000) -+ union { -+ CURL_TYPEOF_CURL_OFF_T ns100; /* time since 1 Jan 1601 in 100ns units */ -+ FILETIME ft; -+ } _now; -+ GetSystemTimeAsFileTime(&_now.ft); -+ tp->tv_usec = (long)((_now.ns100 / 10) % 1000000); -+ tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000); -+ } -+ return 0; -+} -+#endif -+ - struct input { - FILE *in; - size_t bytes_read; /* count up */ -@@ -71,7 +94,7 @@ void dump(const char *text, int num, unsigned char *ptr, size_t size, - fprintf(stderr, "%d %s, %lu bytes (0x%lx)\n", - num, text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -268,7 +291,7 @@ int main(int argc, char **argv) - /* init a multi stack */ - multi_handle = curl_multi_init(); - -- for(i = 0; i - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - -@@ -57,7 +53,7 @@ int main(void) - int msgs_left; /* how many messages are left */ - - /* Allocate one CURL handle per transfer */ -- for(i = 0; imsg == CURLMSG_DONE) { - int idx; - - /* Find out which handle this message is about */ -- for(idx = 0; idxeasy_handle == handles[idx]); - if(found) - break; -@@ -107,7 +104,7 @@ int main(void) - } - - /* remove the transfers and cleanup the handles */ -- for(i = 0; i - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - -@@ -53,7 +49,7 @@ static void dump(const char *text, FILE *stream, unsigned char *ptr, - fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n", - text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -diff --git a/docs/examples/multi-double.c b/docs/examples/multi-double.c -index 62295a92c..99bd736a9 100644 ---- a/docs/examples/multi-double.c -+++ b/docs/examples/multi-double.c -@@ -28,10 +28,6 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - -diff --git a/docs/examples/multi-formadd.c b/docs/examples/multi-formadd.c -index 801b61e6d..58c7e641c 100644 ---- a/docs/examples/multi-formadd.c -+++ b/docs/examples/multi-formadd.c -@@ -33,7 +33,6 @@ - - #include - #include --#include - - #include - -@@ -49,27 +48,29 @@ int main(void) - struct curl_slist *headerlist = NULL; - static const char buf[] = "Expect:"; - -- /* Fill in the file upload field. This makes libcurl load data from -- the given file name when curl_easy_perform() is called. */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "sendfile", -- CURLFORM_FILE, "multi-formadd.c", -- CURLFORM_END); -- -- /* Fill in the filename field */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "filename", -- CURLFORM_COPYCONTENTS, "multi-formadd.c", -- CURLFORM_END); -- -- /* Fill in the submit field too, even if this is rarely needed */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "submit", -- CURLFORM_COPYCONTENTS, "send", -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ /* Fill in the file upload field. This makes libcurl load data from -+ the given file name when curl_easy_perform() is called. */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "sendfile", -+ CURLFORM_FILE, "multi-formadd.c", -+ CURLFORM_END); -+ -+ /* Fill in the filename field */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "filename", -+ CURLFORM_COPYCONTENTS, "multi-formadd.c", -+ CURLFORM_END); -+ -+ /* Fill in the submit field too, even if this is rarely needed */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "submit", -+ CURLFORM_COPYCONTENTS, "send", -+ CURLFORM_END); -+ ) - - curl = curl_easy_init(); - multi_handle = curl_multi_init(); -@@ -84,7 +85,9 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); -- curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ ) - - curl_multi_add_handle(multi_handle, curl); - -@@ -105,8 +108,10 @@ int main(void) - /* always cleanup */ - curl_easy_cleanup(curl); - -- /* then cleanup the formpost chain */ -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* then cleanup the formpost chain */ -+ curl_formfree(formpost); -+ ) - - /* free slist */ - curl_slist_free_all(headerlist); -diff --git a/docs/examples/multi-legacy.c b/docs/examples/multi-legacy.c -index 67575418e..3e7714f40 100644 ---- a/docs/examples/multi-legacy.c -+++ b/docs/examples/multi-legacy.c -@@ -30,9 +30,11 @@ - #include - #include - --/* somewhat unix-specific */ -+/* somewhat Unix-specific */ -+#ifndef _WIN32 - #include - #include -+#endif - - /* curl stuff */ - #include -@@ -57,7 +59,7 @@ int main(void) - int msgs_left; /* how many messages are left */ - - /* Allocate one CURL handle per transfer */ -- for(i = 0; imsg == CURLMSG_DONE) { - int idx; - - /* Find out which handle this message is about */ -- for(idx = 0; idxeasy_handle == handles[idx]); - if(found) - break; -@@ -172,7 +175,7 @@ int main(void) - curl_multi_cleanup(multi_handle); - - /* Free the CURL handles */ -- for(i = 0; i - #include --#include - - #include - -diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c -index f5077850b..0ead96f48 100644 ---- a/docs/examples/multi-single.c -+++ b/docs/examples/multi-single.c -@@ -29,10 +29,6 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - /* curl stuff */ - #include - -diff --git a/docs/examples/multi-uv.c b/docs/examples/multi-uv.c -index 3e967ccd8..27a073194 100644 ---- a/docs/examples/multi-uv.c -+++ b/docs/examples/multi-uv.c -@@ -26,12 +26,12 @@ - * multi_socket API using libuv - * - */ --/* Example application using the multi socket interface to download multiple -- files in parallel, powered by libuv. -+/* Use the socket_action interface to download multiple files in parallel, -+ powered by libuv. - - Requires libuv and (of course) libcurl. - -- See https://nikhilm.github.io/uvbook/ for more information on libuv. -+ See https://docs.libuv.org/en/v1.x/index.html libuv API documentation - */ - - #include -@@ -39,24 +39,30 @@ - #include - #include - --uv_loop_t *loop; --CURLM *curl_handle; --uv_timer_t timeout; -+/* object to pass to the callbacks */ -+struct datauv { -+ uv_timer_t timeout; -+ uv_loop_t *loop; -+ CURLM *multi; -+}; - - typedef struct curl_context_s { - uv_poll_t poll_handle; - curl_socket_t sockfd; -+ struct datauv *uv; - } curl_context_t; - --static curl_context_t *create_curl_context(curl_socket_t sockfd) -+static curl_context_t *create_curl_context(curl_socket_t sockfd, -+ struct datauv *uv) - { - curl_context_t *context; - - context = (curl_context_t *) malloc(sizeof(*context)); - - context->sockfd = sockfd; -+ context->uv = uv; - -- uv_poll_init_socket(loop, &context->poll_handle, sockfd); -+ uv_poll_init_socket(uv->loop, &context->poll_handle, sockfd); - context->poll_handle.data = context; - - return context; -@@ -73,7 +79,7 @@ static void destroy_curl_context(curl_context_t *context) - uv_close((uv_handle_t *) &context->poll_handle, curl_close_cb); - } - --static void add_download(const char *url, int num) -+static void add_download(const char *url, int num, CURLM *multi) - { - char filename[50]; - FILE *file; -@@ -91,11 +97,11 @@ static void add_download(const char *url, int num) - curl_easy_setopt(handle, CURLOPT_WRITEDATA, file); - curl_easy_setopt(handle, CURLOPT_PRIVATE, file); - curl_easy_setopt(handle, CURLOPT_URL, url); -- curl_multi_add_handle(curl_handle, handle); -+ curl_multi_add_handle(multi, handle); - fprintf(stderr, "Added download %s -> %s\n", url, filename); - } - --static void check_multi_info(void) -+static void check_multi_info(curl_context_t *context) - { - char *done_url; - CURLMsg *message; -@@ -103,7 +109,7 @@ static void check_multi_info(void) - CURL *easy_handle; - FILE *file; - -- while((message = curl_multi_info_read(curl_handle, &pending))) { -+ while((message = curl_multi_info_read(context->uv->multi, &pending))) { - switch(message->msg) { - case CURLMSG_DONE: - /* Do not use message data after calling curl_multi_remove_handle() and -@@ -117,7 +123,7 @@ static void check_multi_info(void) - curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, &file); - printf("%s DONE\n", done_url); - -- curl_multi_remove_handle(curl_handle, easy_handle); -+ curl_multi_remove_handle(context->uv->multi, easy_handle); - curl_easy_cleanup(easy_handle); - if(file) { - fclose(file); -@@ -131,73 +137,82 @@ static void check_multi_info(void) - } - } - --static void curl_perform(uv_poll_t *req, int status, int events) -+/* callback from libuv on socket activity */ -+static void on_uv_socket(uv_poll_t *req, int status, int events) - { - int running_handles; - int flags = 0; -- curl_context_t *context; -- -+ curl_context_t *context = (curl_context_t *) req->data; -+ (void)status; - if(events & UV_READABLE) - flags |= CURL_CSELECT_IN; - if(events & UV_WRITABLE) - flags |= CURL_CSELECT_OUT; - -- context = (curl_context_t *) req->data; -- -- curl_multi_socket_action(curl_handle, context->sockfd, flags, -+ curl_multi_socket_action(context->uv->multi, context->sockfd, flags, - &running_handles); -- -- check_multi_info(); -+ check_multi_info(context); - } - --static void on_timeout(uv_timer_t *req) -+/* callback from libuv when timeout expires */ -+static void on_uv_timeout(uv_timer_t *req) - { -- int running_handles; -- curl_multi_socket_action(curl_handle, CURL_SOCKET_TIMEOUT, 0, -- &running_handles); -- check_multi_info(); -+ curl_context_t *context = (curl_context_t *) req->data; -+ if(context) { -+ int running_handles; -+ curl_multi_socket_action(context->uv->multi, CURL_SOCKET_TIMEOUT, 0, -+ &running_handles); -+ check_multi_info(context); -+ } - } - --static int start_timeout(CURLM *multi, long timeout_ms, void *userp) -+/* callback from libcurl to update the timeout expiry */ -+static int cb_timeout(CURLM *multi, long timeout_ms, -+ struct datauv *uv) - { -- if(timeout_ms < 0) { -- uv_timer_stop(&timeout); -- } -+ (void)multi; -+ if(timeout_ms < 0) -+ uv_timer_stop(&uv->timeout); - else { - if(timeout_ms == 0) -- timeout_ms = 1; /* 0 means call socket_action asap */ -- uv_timer_start(&timeout, on_timeout, timeout_ms, 0); -+ timeout_ms = 1; /* 0 means call curl_multi_socket_action asap but NOT -+ within the callback itself */ -+ uv_timer_start(&uv->timeout, on_uv_timeout, timeout_ms, -+ 0); /* do not repeat */ - } - return 0; - } - --static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, -- void *socketp) -+/* callback from libcurl to update socket activity to wait for */ -+static int cb_socket(CURL *easy, curl_socket_t s, int action, -+ struct datauv *uv, -+ void *socketp) - { - curl_context_t *curl_context; - int events = 0; -+ (void)easy; - - switch(action) { - case CURL_POLL_IN: - case CURL_POLL_OUT: - case CURL_POLL_INOUT: - curl_context = socketp ? -- (curl_context_t *) socketp : create_curl_context(s); -+ (curl_context_t *) socketp : create_curl_context(s, uv); - -- curl_multi_assign(curl_handle, s, (void *) curl_context); -+ curl_multi_assign(uv->multi, s, (void *) curl_context); - - if(action != CURL_POLL_IN) - events |= UV_WRITABLE; - if(action != CURL_POLL_OUT) - events |= UV_READABLE; - -- uv_poll_start(&curl_context->poll_handle, events, curl_perform); -+ uv_poll_start(&curl_context->poll_handle, events, on_uv_socket); - break; - case CURL_POLL_REMOVE: - if(socketp) { - uv_poll_stop(&((curl_context_t*)socketp)->poll_handle); - destroy_curl_context((curl_context_t*) socketp); -- curl_multi_assign(curl_handle, s, NULL); -+ curl_multi_assign(uv->multi, s, NULL); - } - break; - default: -@@ -209,28 +224,31 @@ static int handle_socket(CURL *easy, curl_socket_t s, int action, void *userp, - - int main(int argc, char **argv) - { -- loop = uv_default_loop(); -+ struct datauv uv = { 0 }; -+ int running_handles; - - if(argc <= 1) - return 0; - -- if(curl_global_init(CURL_GLOBAL_ALL)) { -- fprintf(stderr, "Could not init curl\n"); -- return 1; -- } -+ curl_global_init(CURL_GLOBAL_ALL); - -- uv_timer_init(loop, &timeout); -+ uv.loop = uv_default_loop(); -+ uv_timer_init(uv.loop, &uv.timeout); - -- curl_handle = curl_multi_init(); -- curl_multi_setopt(curl_handle, CURLMOPT_SOCKETFUNCTION, handle_socket); -- curl_multi_setopt(curl_handle, CURLMOPT_TIMERFUNCTION, start_timeout); -+ uv.multi = curl_multi_init(); -+ curl_multi_setopt(uv.multi, CURLMOPT_SOCKETFUNCTION, cb_socket); -+ curl_multi_setopt(uv.multi, CURLMOPT_SOCKETDATA, &uv); -+ curl_multi_setopt(uv.multi, CURLMOPT_TIMERFUNCTION, cb_timeout); -+ curl_multi_setopt(uv.multi, CURLMOPT_TIMERDATA, &uv); - - while(argc-- > 1) { -- add_download(argv[argc], argc); -+ add_download(argv[argc], argc, uv.multi); - } - -- uv_run(loop, UV_RUN_DEFAULT); -- curl_multi_cleanup(curl_handle); -+ /* kickstart the thing */ -+ curl_multi_socket_action(uv.multi, CURL_SOCKET_TIMEOUT, 0, &running_handles); -+ uv_run(uv.loop, UV_RUN_DEFAULT); -+ curl_multi_cleanup(uv.multi); - - return 0; - } -diff --git a/docs/examples/multithread.c b/docs/examples/multithread.c -index cc4ce7c12..299edd57a 100644 ---- a/docs/examples/multithread.c -+++ b/docs/examples/multithread.c -@@ -75,7 +75,7 @@ int main(int argc, char **argv) - /* Must initialize libcurl before any threads are started */ - curl_global_init(CURL_GLOBAL_ALL); - -- for(i = 0; i< NUMT; i++) { -+ for(i = 0; i < NUMT; i++) { - int error = pthread_create(&tid[i], - NULL, /* default attributes please */ - pull_one_url, -@@ -87,7 +87,7 @@ int main(int argc, char **argv) - } - - /* now wait for all threads to terminate */ -- for(i = 0; i< NUMT; i++) { -+ for(i = 0; i < NUMT; i++) { - pthread_join(tid[i], NULL); - fprintf(stderr, "Thread %d terminated\n", i); - } -diff --git a/docs/examples/persistent.c b/docs/examples/persistent.c -index 4be7d6f2a..be5e8c33e 100644 ---- a/docs/examples/persistent.c -+++ b/docs/examples/persistent.c -@@ -26,7 +26,7 @@ - * - */ - #include --#include -+ - #include - - int main(void) -diff --git a/docs/examples/post-callback.c b/docs/examples/post-callback.c -index 311bc3cae..1a213cb2d 100644 ---- a/docs/examples/post-callback.c -+++ b/docs/examples/post-callback.c -@@ -73,7 +73,7 @@ int main(void) - wt.readptr = data; - wt.sizeleft = strlen(data); - -- /* In windows, this inits the winsock stuff */ -+ /* In Windows, this inits the Winsock stuff */ - res = curl_global_init(CURL_GLOBAL_DEFAULT); - /* Check for errors */ - if(res != CURLE_OK) { -diff --git a/docs/examples/postit2-formadd.c b/docs/examples/postit2-formadd.c -index 02e50aa3d..0d9034612 100644 ---- a/docs/examples/postit2-formadd.c -+++ b/docs/examples/postit2-formadd.c -@@ -59,27 +59,29 @@ int main(int argc, char *argv[]) - - curl_global_init(CURL_GLOBAL_ALL); - -- /* Fill in the file upload field */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "sendfile", -- CURLFORM_FILE, "postit2-formadd.c", -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ /* Fill in the file upload field */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "sendfile", -+ CURLFORM_FILE, "postit2-formadd.c", -+ CURLFORM_END); - -- /* Fill in the filename field */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "filename", -- CURLFORM_COPYCONTENTS, "postit2-formadd.c", -- CURLFORM_END); -+ /* Fill in the filename field */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "filename", -+ CURLFORM_COPYCONTENTS, "postit2-formadd.c", -+ CURLFORM_END); - - -- /* Fill in the submit field too, even if this is rarely needed */ -- curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "submit", -- CURLFORM_COPYCONTENTS, "send", -- CURLFORM_END); -+ /* Fill in the submit field too, even if this is rarely needed */ -+ curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "submit", -+ CURLFORM_COPYCONTENTS, "send", -+ CURLFORM_END); -+ ) - - curl = curl_easy_init(); - /* initialize custom header list (stating that Expect: 100-continue is not -@@ -91,7 +93,9 @@ int main(int argc, char *argv[]) - if((argc == 2) && (!strcmp(argv[1], "noexpectheader"))) - /* only disable 100-continue header if explicitly requested */ - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); -- curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ ) - - /* Perform the request, res gets the return code */ - res = curl_easy_perform(curl); -@@ -103,8 +107,11 @@ int main(int argc, char *argv[]) - /* always cleanup */ - curl_easy_cleanup(curl); - -- /* then cleanup the formpost chain */ -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* then cleanup the formpost chain */ -+ curl_formfree(formpost); -+ ) -+ - /* free slist */ - curl_slist_free_all(headerlist); - } -diff --git a/docs/examples/sendrecv.c b/docs/examples/sendrecv.c -index 0b7e86a3f..93e06099c 100644 ---- a/docs/examples/sendrecv.c -+++ b/docs/examples/sendrecv.c -@@ -48,9 +48,12 @@ static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms) - * warning: conversion to 'long unsigned int' from 'curl_socket_t' {aka 'int'} - * may change the sign of the result [-Wsign-conversion] - */ --#if defined(__GNUC__) && defined(__CYGWIN__) -+#if defined(__GNUC__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wsign-conversion" -+#elif defined(_MSC_VER) -+#pragma warning(push) -+#pragma warning(disable:4127) /* conditional expression is constant */ - #endif - FD_SET(sockfd, &errfd); /* always check for error */ - -@@ -60,8 +63,10 @@ static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms) - else { - FD_SET(sockfd, &outfd); - } --#if defined(__GNUC__) && defined(__CYGWIN__) -+#if defined(__GNUC__) - #pragma GCC diagnostic pop -+#elif defined(_MSC_VER) -+#pragma warning(pop) - #endif - - /* select() returns the number of signalled sockets or -1 */ -diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c -index 0d090ed81..31a320124 100644 ---- a/docs/examples/sepheaders.c -+++ b/docs/examples/sepheaders.c -@@ -27,7 +27,6 @@ - */ - #include - #include --#include - - #include - -diff --git a/docs/examples/simplessl.c b/docs/examples/simplessl.c -index 7145493a6..fcbb5a460 100644 ---- a/docs/examples/simplessl.c -+++ b/docs/examples/simplessl.c -@@ -83,6 +83,10 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_URL, "HTTPS://your.favourite.ssl.site"); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, headerfile); - -+#ifdef _MSC_VER -+#pragma warning(push) -+#pragma warning(disable:4127) /* conditional expression is constant */ -+#endif - do { /* dummy loop, just to break out from */ - if(pEngine) { - /* use crypto engine */ -@@ -94,7 +98,7 @@ int main(void) - if(curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L) != CURLE_OK) { - /* set the crypto engine as default */ - /* only needed for the first time you load -- a engine in a curl object... */ -+ an engine in a curl object... */ - fprintf(stderr, "cannot set crypto engine as default\n"); - break; - } -@@ -133,6 +137,9 @@ int main(void) - - /* we are done... */ - } while(0); -+#ifdef _MSC_VER -+#pragma warning(pop) -+#endif - /* always cleanup */ - curl_easy_cleanup(curl); - } -diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c -index ab61b2fb0..6c495f4ae 100644 ---- a/docs/examples/synctime.c -+++ b/docs/examples/synctime.c -@@ -165,7 +165,7 @@ size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, - if(RetVal == 7) { - int i; - SYSTime.wMilliseconds = 500; /* adjust to midpoint, 0.5 sec */ -- for(i = 0; i<12; i++) { -+ for(i = 0; i < 12; i++) { - if(strcmp(MthStr[i], TmpStr2) == 0) { - SYSTime.wMonth = i + 1; - break; -@@ -250,7 +250,7 @@ int conf_init(conf_t *conf) - int i; - - *conf->http_proxy = 0; -- for(i = 0; iproxy_user[i] = 0; /* Clean up password from memory */ - *conf->timeserver = 0; - return 1; -diff --git a/docs/examples/threaded-ssl.c b/docs/examples/threaded-ssl.c -index f58e44741..c903fced0 100644 ---- a/docs/examples/threaded-ssl.c -+++ b/docs/examples/threaded-ssl.c -@@ -27,13 +27,13 @@ - * - */ - /* A multi-threaded example that uses pthreads and fetches 4 remote files at -- * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS -- * (libgcrypt) so far. -+ * once over HTTPS. - * -- * OpenSSL docs for this: -- * https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html -- * gcrypt docs for this: -- * https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html -+ * Recent versions of OpenSSL and GnuTLS are thread safe by design, assuming -+ * support for the underlying OS threading API is built-in. Older revisions -+ * of this example demonstrated locking callbacks for the SSL library, which -+ * are no longer necessary. An older revision with callbacks can be found at -+ * https://github.com/curl/curl/blob/curl-7_88_1/docs/examples/threaded-ssl.c - */ - - #define USE_OPENSSL /* or USE_GNUTLS accordingly */ -@@ -44,71 +44,6 @@ - - #define NUMT 4 - --/* we have this global to let the callback get easy access to it */ --static pthread_mutex_t *lockarray; -- --#ifdef USE_OPENSSL --#include --static void lock_callback(int mode, int type, char *file, int line) --{ -- (void)file; -- (void)line; -- if(mode & CRYPTO_LOCK) { -- pthread_mutex_lock(&(lockarray[type])); -- } -- else { -- pthread_mutex_unlock(&(lockarray[type])); -- } --} -- --static unsigned long thread_id(void) --{ -- unsigned long ret; -- -- ret = (unsigned long)pthread_self(); -- return ret; --} -- --static void init_locks(void) --{ -- int i; -- -- lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * -- sizeof(pthread_mutex_t)); -- for(i = 0; i --#include -- --GCRY_THREAD_OPTION_PTHREAD_IMPL; -- --void init_locks(void) --{ -- gcry_control(GCRYCTL_SET_THREAD_CBS); --} -- --#define kill_locks() --#endif -- - /* List of URLs to fetch.*/ - const char * const urls[]= { - "https://www.example.com/", -@@ -143,9 +78,7 @@ int main(int argc, char **argv) - /* Must initialize libcurl before any threads are started */ - curl_global_init(CURL_GLOBAL_ALL); - -- init_locks(); -- -- for(i = 0; i< NUMT; i++) { -+ for(i = 0; i < NUMT; i++) { - int error = pthread_create(&tid[i], - NULL, /* default attributes please */ - pull_one_url, -@@ -157,12 +90,10 @@ int main(int argc, char **argv) - } - - /* now wait for all threads to terminate */ -- for(i = 0; i< NUMT; i++) { -+ for(i = 0; i < NUMT; i++) { - pthread_join(tid[i], NULL); - fprintf(stderr, "Thread %d terminated\n", i); - } - -- kill_locks(); -- - return 0; - } -diff --git a/docs/examples/unixsocket.c b/docs/examples/unixsocket.c -index 90c655917..299a121d9 100644 ---- a/docs/examples/unixsocket.c -+++ b/docs/examples/unixsocket.c -@@ -22,7 +22,7 @@ - * - ***************************************************************************/ - /* -- * Access HTTP server over unix domain socket -+ * Access HTTP server over Unix domain socket - * - */ - #include -diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c -index f95d57464..9ed7da5a8 100644 ---- a/docs/examples/url2file.c -+++ b/docs/examples/url2file.c -@@ -27,7 +27,6 @@ - */ - #include - #include --#include - - #include - -diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c -index b35d98203..7b338cd98 100644 ---- a/docs/examples/usercertinmem.c -+++ b/docs/examples/usercertinmem.c -@@ -157,7 +157,7 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) - printf("Use Key failed\n"); - } - -- /* free resources that have been allocated by openssl functions */ -+ /* free resources that have been allocated by OpenSSL functions */ - if(bio) - BIO_free(bio); - -diff --git a/docs/examples/websocket.c b/docs/examples/websocket.c -index 039b4f8b9..996f2a024 100644 ---- a/docs/examples/websocket.c -+++ b/docs/examples/websocket.c -@@ -27,7 +27,13 @@ - */ - #include - #include -+#ifdef _WIN32 -+#include -+#define sleep(s) Sleep((DWORD)(s)) -+#else - #include -+#endif -+ - #include - - static int ping(CURL *curl, const char *send_payload) -@@ -68,16 +74,13 @@ static int recv_pong(CURL *curl, const char *expected_payload) - return (int)result; - } - --static int recv_any(CURL *curl) -+static CURLcode recv_any(CURL *curl) - { - size_t rlen; - const struct curl_ws_frame *meta; - char buffer[256]; -- CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta); -- if(result) -- return result; - -- return 0; -+ return curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta); - } - - /* close the connection */ -diff --git a/docs/examples/xmlstream.c b/docs/examples/xmlstream.c -index 76a8e48cc..d779e6e7c 100644 ---- a/docs/examples/xmlstream.c -+++ b/docs/examples/xmlstream.c -@@ -36,7 +36,6 @@ - #include - #include - #include --#include - - #include - #include -diff --git a/docs/internals/BUFQ.md b/docs/internals/BUFQ.md -new file mode 100644 -index 000000000..bb5778452 ---- /dev/null -+++ b/docs/internals/BUFQ.md -@@ -0,0 +1,188 @@ -+ -+ -+# bufq -+ -+This is an internal module for managing I/O buffers. A `bufq` can be written -+to and read from. It manages read and write positions and has a maximum size. -+ -+## read/write -+ -+Its basic read/write functions have a similar signature and return code handling -+as many internal Curl read and write ones. -+ -+ -+``` -+ssize_t Curl_bufq_write(struct bufq *q, const unsigned char *buf, size_t len, CURLcode *err); -+ -+- returns the length written into `q` or -1 on error. -+- writing to a full `q` returns -1 and set *err to CURLE_AGAIN -+ -+ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, CURLcode *err); -+ -+- returns the length read from `q` or -1 on error. -+- reading from an empty `q` returns -1 and set *err to CURLE_AGAIN -+ -+``` -+ -+To pass data into a `bufq` without an extra copy, read callbacks can be used. -+ -+``` -+typedef ssize_t Curl_bufq_reader(void *reader_ctx, unsigned char *buf, size_t len, -+ CURLcode *err); -+ -+ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, void *reader_ctx, -+ CURLcode *err); -+``` -+ -+`Curl_bufq_slurp()` invokes the given `reader` callback, passing it its own -+internal buffer memory to write to. It may invoke the `reader` several times, -+as long as it has space and while the `reader` always returns the length that -+was requested. There are variations of `slurp` that call the `reader` at most -+once or only read in a maximum amount of bytes. -+ -+The analog mechanism for write out buffer data is: -+ -+``` -+typedef ssize_t Curl_bufq_writer(void *writer_ctx, const unsigned char *buf, size_t len, -+ CURLcode *err); -+ -+ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, void *writer_ctx, -+ CURLcode *err); -+``` -+ -+`Curl_bufq_pass()` invokes the `writer`, passing its internal memory and -+remove the amount that `writer` reports. -+ -+## peek and skip -+ -+It is possible to get access to the memory of data stored in a `bufq` with: -+ -+``` -+bool Curl_bufq_peek(const struct bufq *q, const unsigned char **pbuf, size_t *plen); -+``` -+ -+On returning TRUE, `pbuf` points to internal memory with `plen` bytes that one -+may read. This is only valid until another operation on `bufq` is performed. -+ -+Instead of reading `bufq` data, one may simply skip it: -+ -+``` -+void Curl_bufq_skip(struct bufq *q, size_t amount); -+``` -+ -+This removes `amount` number of bytes from the `bufq`. -+ -+## unwrite -+ -+It is possible to undo writes by calling: -+ -+``` -+CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len); -+``` -+ -+This will remove `len` bytes from the end of the bufq again. When removing -+more bytes than are present, CURLE_AGAIN is returned and the bufq will be -+empty. -+ -+## lifetime -+ -+`bufq` is initialized and freed similar to the `dynbuf` module. Code using -+`bufq` holds a `struct bufq` somewhere. Before it uses it, it invokes: -+ -+``` -+void Curl_bufq_init(struct bufq *q, size_t chunk_size, size_t max_chunks); -+``` -+ -+The `bufq` is told how many "chunks" of data it shall hold at maximum and how -+large those "chunks" should be. There are some variants of this, allowing for -+more options. How "chunks" are handled in a `bufq` is presented in the section -+about memory management. -+ -+The user of the `bufq` has the responsibility to call: -+ -+``` -+void Curl_bufq_free(struct bufq *q); -+``` -+to free all resources held by `q`. It is possible to reset a `bufq` to empty via: -+ -+``` -+void Curl_bufq_reset(struct bufq *q); -+``` -+ -+## memory management -+ -+Internally, a `bufq` uses allocation of fixed size, e.g. the "chunk_size", up -+to a maximum number, e.g. "max_chunks". These chunks are allocated on demand, -+therefore writing to a `bufq` may return `CURLE_OUT_OF_MEMORY`. Once the max -+number of chunks are used, the `bufq` reports that it is "full". -+ -+Each chunks has a `read` and `write` index. A `bufq` keeps its chunks in a -+list. Reading happens always at the head chunk, writing always goes to the -+tail chunk. When the head chunk becomes empty, it is removed. When the tail -+chunk becomes full, another chunk is added to the end of the list, becoming -+the new tail. -+ -+Chunks that are no longer used are returned to a `spare` list by default. If -+the `bufq` is created with option `BUFQ_OPT_NO_SPARES` those chunks are freed -+right away. -+ -+If a `bufq` is created with a `bufc_pool`, the no longer used chunks are -+returned to the pool. Also `bufq` asks the pool for a chunk when it needs one. -+More in section "pools". -+ -+## empty, full and overflow -+ -+One can ask about the state of a `bufq` with methods such as -+`Curl_bufq_is_empty(q)`, `Curl_bufq_is_full(q)`, etc. The amount of data held -+by a `bufq` is the sum of the data in all its chunks. This is what is reported -+by `Curl_bufq_len(q)`. -+ -+Note that a `bufq` length and it being "full" are only loosely related. A -+simple example: -+ -+* create a `bufq` with chunk_size=1000 and max_chunks=4. -+* write 4000 bytes to it, it reports "full" -+* read 1 bytes from it, it still reports "full" -+* read 999 more bytes from it, and it is no longer "full" -+ -+The reason for this is that full really means: *bufq uses max_chunks and the -+last one cannot be written to*. -+ -+When you read 1 byte from the head chunk in the example above, the head still -+hold 999 unread bytes. Only when those are also read, can the head chunk be -+removed and a new tail be added. -+ -+There is another variation to this. If you initialized a `bufq` with option -+`BUFQ_OPT_SOFT_LIMIT`, it allows writes **beyond** the `max_chunks`. It -+reports **full**, but one can **still** write. This option is necessary, if -+partial writes need to be avoided. It means that you need other checks to keep -+the `bufq` from growing ever larger and larger. -+ -+ -+## pools -+ -+A `struct bufc_pool` may be used to create chunks for a `bufq` and keep spare -+ones around. It is initialized and used via: -+ -+``` -+void Curl_bufcp_init(struct bufc_pool *pool, size_t chunk_size, size_t spare_max); -+ -+void Curl_bufq_initp(struct bufq *q, struct bufc_pool *pool, size_t max_chunks, int opts); -+``` -+ -+The pool gets the size and the mount of spares to keep. The `bufq` gets the -+pool and the `max_chunks`. It no longer needs to know the chunk sizes, as -+those are managed by the pool. -+ -+A pool can be shared between many `bufq`s, as long as all of them operate in -+the same thread. In curl that would be true for all transfers using the same -+multi handle. The advantages of a pool are: -+ -+* when all `bufq`s are empty, only memory for `max_spare` chunks in the pool -+ is used. Empty `bufq`s holds no memory. -+* the latest spare chunk is the first to be handed out again, no matter which -+ `bufq` needs it. This keeps the footprint of "recently used" memory smaller. -diff --git a/docs/internals/BUFREF.md b/docs/internals/BUFREF.md -new file mode 100644 -index 000000000..9a8b506b5 ---- /dev/null -+++ b/docs/internals/BUFREF.md -@@ -0,0 +1,86 @@ -+ -+ -+# bufref -+ -+This is an internal module for handling buffer references. A referenced -+buffer is associated with its destructor function that is implicitly called -+when the reference is invalidated. Once referenced, a buffer cannot be -+reallocated. -+ -+A data length is stored within the reference for binary data handling -+purposes; it is not used by the bufref API. -+ -+The `struct bufref` is used to hold data referencing a buffer. The members of -+that structure **MUST NOT** be accessed or modified without using the dedicated -+bufref API. -+ -+## `init` -+ -+```c -+void Curl_bufref_init(struct bufref *br); -+``` -+ -+Initializes a `bufref` structure. This function **MUST** be called before any -+other operation is performed on the structure. -+ -+Upon completion, the referenced buffer is `NULL` and length is zero. -+ -+This function may also be called to bypass referenced buffer destruction while -+invalidating the current reference. -+ -+## `free` -+ -+```c -+void Curl_bufref_free(struct bufref *br); -+``` -+ -+Destroys the previously referenced buffer using its destructor and -+reinitializes the structure for a possible subsequent reuse. -+ -+## `set` -+ -+```c -+void Curl_bufref_set(struct bufref *br, const void *buffer, size_t length, -+ void (*destructor)(void *)); -+``` -+ -+Releases the previously referenced buffer, then assigns the new `buffer` to -+the structure, associated with its `destructor` function. The latter can be -+specified as `NULL`: this is the case when the referenced buffer is static. -+ -+if `buffer` is NULL, `length` must be zero. -+ -+## `memdup` -+ -+```c -+CURLcode Curl_bufref_memdup(struct bufref *br, const void *data, size_t length); -+``` -+ -+Releases the previously referenced buffer, then duplicates the `length`-byte -+`data` into a buffer allocated via `malloc()` and references the latter -+associated with destructor `curl_free()`. -+ -+An additional trailing byte is allocated and set to zero as a possible string -+null-terminator; it is not counted in the stored length. -+ -+Returns `CURLE_OK` if successful, else `CURLE_OUT_OF_MEMORY`. -+ -+## `ptr` -+ -+```c -+const unsigned char *Curl_bufref_ptr(const struct bufref *br); -+``` -+ -+Returns a `const unsigned char *` to the referenced buffer. -+ -+## `len` -+ -+```c -+size_t Curl_bufref_len(const struct bufref *br); -+``` -+ -+Returns the stored length of the referenced buffer. -diff --git a/docs/internals/CHECKSRC.md b/docs/internals/CHECKSRC.md -new file mode 100644 -index 000000000..16eb96c75 ---- /dev/null -+++ b/docs/internals/CHECKSRC.md -@@ -0,0 +1,190 @@ -+ -+ -+# checksrc -+ -+This is the tool we use within the curl project to scan C source code and -+check that it adheres to our [Source Code Style guide](CODE_STYLE.md). -+ -+## Usage -+ -+ checksrc.pl [options] [file1] [file2] ... -+ -+## Command line options -+ -+`-W[file]` skip that file and exclude it from being checked. Helpful -+when, for example, one of the files is generated. -+ -+`-D[dir]` directory name to prepend to filenames when accessing them. -+ -+`-h` shows the help output, that also lists all recognized warnings -+ -+## What does `checksrc` warn for? -+ -+`checksrc` does not check and verify the code against the entire style guide. -+The script is an effort to detect the most common mistakes and syntax mistakes -+that contributors make before they get accustomed to our code style. Heck, -+many of us regulars do the mistakes too and this script helps us keep the code -+in shape. -+ -+ checksrc.pl -h -+ -+Lists how to use the script and it lists all existing warnings it has and -+problems it detects. At the time of this writing, the existing `checksrc` -+warnings are: -+ -+- `ASSIGNWITHINCONDITION`: Assignment within a conditional expression. The -+ code style mandates the assignment to be done outside of it. -+ -+- `ASTERISKNOSPACE`: A pointer was declared like `char* name` instead of the -+ more appropriate `char *name` style. The asterisk should sit next to the -+ name. -+ -+- `ASTERISKSPACE`: A pointer was declared like `char * name` instead of the -+ more appropriate `char *name` style. The asterisk should sit right next to -+ the name without a space in between. -+ -+- `BADCOMMAND`: There is a bad `checksrc` instruction in the code. See the -+ **Ignore certain warnings** section below for details. -+ -+- `BANNEDFUNC`: A banned function was used. The functions sprintf, vsprintf, -+ strcat, strncat, gets are **never** allowed in curl source code. -+ -+- `BRACEELSE`: '} else' on the same line. The else is supposed to be on the -+ following line. -+ -+- `BRACEPOS`: wrong position for an open brace (`{`). -+ -+- `BRACEWHILE`: more than once space between end brace and while keyword -+ -+- `COMMANOSPACE`: a comma without following space -+ -+- `COPYRIGHT`: the file is missing a copyright statement -+ -+- `CPPCOMMENTS`: `//` comment detected, that is not C89 compliant -+ -+- `DOBRACE`: only use one space after do before open brace -+ -+- `EMPTYLINEBRACE`: found empty line before open brace -+ -+- `EQUALSNOSPACE`: no space after `=` sign -+ -+- `EQUALSNULL`: comparison with `== NULL` used in if/while. We use `!var`. -+ -+- `EXCLAMATIONSPACE`: space found after exclamations mark -+ -+- `FOPENMODE`: `fopen()` needs a macro for the mode string, use it -+ -+- `INDENTATION`: detected a wrong start column for code. Note that this -+ warning only checks some specific places and can certainly miss many bad -+ indentations. -+ -+- `LONGLINE`: A line is longer than 79 columns. -+ -+- `MULTISPACE`: Multiple spaces were found where only one should be used. -+ -+- `NOSPACEEQUALS`: An equals sign was found without preceding space. We prefer -+ `a = 2` and *not* `a=2`. -+ -+- `NOTEQUALSZERO`: check found using `!= 0`. We use plain `if(var)`. -+ -+- `ONELINECONDITION`: do not put the conditional block on the same line as `if()` -+ -+- `OPENCOMMENT`: File ended with a comment (`/*`) still "open". -+ -+- `PARENBRACE`: `){` was used without sufficient space in between. -+ -+- `RETURNNOSPACE`: `return` was used without space between the keyword and the -+ following value. -+ -+- `SEMINOSPACE`: There was no space (or newline) following a semicolon. -+ -+- `SIZEOFNOPAREN`: Found use of sizeof without parentheses. We prefer -+ `sizeof(int)` style. -+ -+- `SNPRINTF` - Found use of `snprintf()`. Since we use an internal replacement -+ with a different return code etc, we prefer `msnprintf()`. -+ -+- `SPACEAFTERPAREN`: there was a space after open parenthesis, `( text`. -+ -+- `SPACEBEFORECLOSE`: there was a space before a close parenthesis, `text )`. -+ -+- `SPACEBEFORECOMMA`: there was a space before a comma, `one , two`. -+ -+- `SPACEBEFOREPAREN`: there was a space before an open parenthesis, `if (`, -+ where one was not expected -+ -+- `SPACESEMICOLON`: there was a space before semicolon, ` ;`. -+ -+- `TABS`: TAB characters are not allowed -+ -+- `TRAILINGSPACE`: Trailing whitespace on the line -+ -+- `TYPEDEFSTRUCT`: we frown upon (most) typedefed structs -+ -+- `UNUSEDIGNORE`: a `checksrc` inlined warning ignore was asked for but not -+ used, that is an ignore that should be removed or changed to get used. -+ -+### Extended warnings -+ -+Some warnings are quite computationally expensive to perform, so they are -+turned off by default. To enable these warnings, place a `.checksrc` file in -+the directory where they should be activated with commands to enable the -+warnings you are interested in. The format of the file is to enable one -+warning per line like so: `enable ` -+ -+Currently these are the extended warnings which can be enabled: -+ -+- `COPYRIGHTYEAR`: the current changeset has not updated the copyright year in -+ the source file -+ -+- `STRERROR`: use of banned function strerror() -+ -+- `STDERR`: use of banned variable `stderr` -+ -+## Ignore certain warnings -+ -+Due to the nature of the source code and the flaws of the `checksrc` tool, -+there is sometimes a need to ignore specific warnings. `checksrc` allows a few -+different ways to do this. -+ -+### Inline ignore -+ -+You can control what to ignore within a specific source file by providing -+instructions to `checksrc` in the source code itself. See examples below. The -+instruction can ask to ignore a specific warning a specific number of times or -+you ignore all of them until you mark the end of the ignored section. -+ -+Inline ignores are only done for that single specific source code file. -+ -+Example -+ -+ /* !checksrc! disable LONGLINE all */ -+ -+This ignores the warning for overly long lines until it is re-enabled with: -+ -+ /* !checksrc! enable LONGLINE */ -+ -+If the enabling is not performed before the end of the file, it is enabled -+again automatically for the next file. -+ -+You can also opt to ignore just N violations so that if you have a single long -+line you just cannot shorten and is agreed to be fine anyway: -+ -+ /* !checksrc! disable LONGLINE 1 */ -+ -+... and the warning for long lines is enabled again automatically after it has -+ignored that single warning. The number `1` can of course be changed to any -+other integer number. It can be used to make sure only the exact intended -+instances are ignored and nothing extra. -+ -+### Directory wide ignore patterns -+ -+This is a method we have transitioned away from. Use inline ignores as far as -+possible. -+ -+Make a `checksrc.skip` file in the directory of the source code with the -+false positive, and include the full offending line into this file. -diff --git a/docs/internals/CLIENT-READERS.md b/docs/internals/CLIENT-READERS.md -new file mode 100644 -index 000000000..073063845 ---- /dev/null -+++ b/docs/internals/CLIENT-READERS.md -@@ -0,0 +1,132 @@ -+ -+ -+# curl client readers -+ -+Client readers is a design in the internals of libcurl, not visible in its public API. They were started -+in curl v8.7.0. This document describes the concepts, its high level implementation and the motivations. -+ -+## Naming -+ -+`libcurl` operates between clients and servers. A *client* is the application using libcurl, like the command line tool `curl` itself. Data to be uploaded to a server is **read** from the client and **sent** to the server, the servers response is **received** by `libcurl` and then **written** to the client. -+ -+With this naming established, client readers are concerned with providing data from the application to the server. Applications register callbacks via `CURLOPT_READFUNCTION`, data via `CURLOPT_POSTFIELDS` and other options to be used by `libcurl` when the request is send. -+ -+## Invoking -+ -+The transfer loop that sends and receives, is using `Curl_client_read()` to get more data to send for a transfer. If no specific reader has been installed yet, the default one that uses `CURLOPT_READFUNCTION` is added. The prototype is -+ -+``` -+CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen, -+ size_t *nread, bool *eos); -+``` -+The arguments are the transfer to read for, a buffer to hold the read data, its length, the actual number of bytes placed into the buffer and the `eos` (*end of stream*) flag indicating that no more data is available. The `eos` flag may be set for a read amount, if that amount was the last. That way curl can avoid to read an additional time. -+ -+The implementation of `Curl_client_read()` uses a chain of *client reader* instances to get the data. This is similar to the design of *client writers*. The chain of readers allows processing of the data to send. -+ -+The definition of a reader is: -+ -+``` -+struct Curl_crtype { -+ const char *name; /* writer name. */ -+ CURLcode (*do_init)(struct Curl_easy *data, struct Curl_creader *writer); -+ CURLcode (*do_read)(struct Curl_easy *data, struct Curl_creader *reader, -+ char *buf, size_t blen, size_t *nread, bool *eos); -+ void (*do_close)(struct Curl_easy *data, struct Curl_creader *reader); -+ bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader); -+ curl_off_t (*total_length)(struct Curl_easy *data, -+ struct Curl_creader *reader); -+ CURLcode (*resume_from)(struct Curl_easy *data, -+ struct Curl_creader *reader, curl_off_t offset); -+ CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader); -+}; -+ -+struct Curl_creader { -+ const struct Curl_crtype *crt; /* type implementation */ -+ struct Curl_creader *next; /* Downstream reader. */ -+ Curl_creader_phase phase; /* phase at which it operates */ -+}; -+``` -+ -+`Curl_creader` is a reader instance with a `next` pointer to form the chain. It as a type `crt` which provides the implementation. The main callback is `do_read()` which provides the data to the caller. The others are for setup and tear down. `needs_rewind()` is explained further below. -+ -+## Phases and Ordering -+ -+Since client readers may transform the data being read through the chain, the order in which they are called is relevant for the outcome. When a reader is created, it gets the `phase` property in which it operates. Reader phases are defined like: -+ -+``` -+typedef enum { -+ CURL_CR_NET, /* data send to the network (connection filters) */ -+ CURL_CR_TRANSFER_ENCODE, /* add transfer-encodings */ -+ CURL_CR_PROTOCOL, /* before transfer, but after content decoding */ -+ CURL_CR_CONTENT_ENCODE, /* add content-encodings */ -+ CURL_CR_CLIENT /* data read from client */ -+} Curl_creader_phase; -+``` -+ -+If a reader for phase `PROTOCOL` is added to the chain, it is always added *after* any `NET` or `TRANSFER_ENCODE` readers and *before* and `CONTENT_ENCODE` and `CLIENT` readers. If there is already a reader for the same phase, the new reader is added before the existing one(s). -+ -+### Example: `chunked` reader -+ -+In `http_chunks.c` a client reader for chunked uploads is implemented. This one operates at phase `CURL_CR_TRANSFER_ENCODE`. Any data coming from the reader "below" has the HTTP/1.1 chunk handling applied and returned to the caller. -+ -+When this reader sees an `eos` from below, it generates the terminal chunk, adding trailers if provided by the application. When that last chunk is fully returned, it also sets `eos` to the caller. -+ -+### Example: `lineconv` reader -+ -+In `sendf.c` a client reader that does line-end conversions is implemented. It operates at `CURL_CR_CONTENT_ENCODE` and converts any "\n" to "\r\n". This is used for FTP ASCII uploads or when the general `crlf` options has been set. -+ -+### Example: `null` reader -+ -+Implemented in `sendf.c` for phase `CURL_CR_CLIENT`, this reader has the simple job of providing transfer bytes of length 0 to the caller, immediately indicating an `eos`. This reader is installed by HTTP for all GET/HEAD requests and when authentication is being negotiated. -+ -+### Example: `buf` reader -+ -+Implemented in `sendf.c` for phase `CURL_CR_CLIENT`, this reader get a buffer pointer and a length and provides exactly these bytes. This one is used in HTTP for sending `postfields` provided by the application. -+ -+## Request retries -+ -+Sometimes it is necessary to send a request with client data again. Transfer handling can inquire via `Curl_client_read_needs_rewind()` if a rewind (e.g. a reset of the client data) is necessary. This asks all installed readers if they need it and give `FALSE` of none does. -+ -+## Upload Size -+ -+Many protocols need to know the amount of bytes delivered by the client readers in advance. They may invoke `Curl_creader_total_length(data)` to retrieve that. However, not all reader chains know the exact value beforehand. In that case, the call returns `-1` for "unknown". -+ -+Even if the length of the "raw" data is known, the length that is send may not. Example: with option `--crlf` the uploaded content undergoes line-end conversion. The line converting reader does not know in advance how many newlines it may encounter. Therefore it must return `-1` for any positive raw content length. -+ -+In HTTP, once the correct client readers are installed, the protocol asks the readers for the total length. If that is known, it can set `Content-Length:` accordingly. If not, it may choose to add an HTTP "chunked" reader. -+ -+In addition, there is `Curl_creader_client_length(data)` which gives the total length as reported by the reader in phase `CURL_CR_CLIENT` without asking other readers that may transform the raw data. This is useful in estimating the size of an upload. The HTTP protocol uses this to determine if `Expect: 100-continue` shall be done. -+ -+## Resuming -+ -+Uploads can start at a specific offset, if so requested. The "resume from" that offset. This applies to the reader in phase `CURL_CR_CLIENT` that delivers the "raw" content. Resumption can fail if the installed reader does not support it or if the offset is too large. -+ -+The total length reported by the reader changes when resuming. Example: resuming an upload of 100 bytes by 25 reports a total length of 75 afterwards. -+ -+If `resume_from()` is invoked twice, it is additive. There is currently no way to undo a resume. -+ -+## Rewinding -+ -+When a request is retried, installed client readers are discarded and replaced by new ones. This works only if the new readers upload the same data. For many readers, this is not an issue. The "null" reader always does the same. Also the `buf` reader, initialized with the same buffer, does this. -+ -+Readers operating on callbacks to the application need to "rewind" the underlying content. For example, when reading from a `FILE*`, the reader needs to `fseek()` to the beginning. The following methods are used: -+ -+1. `Curl_creader_needs_rewind(data)`: tells if a rewind is necessary, given the current state of the reader chain. If nothing really has been read so far, this returns `FALSE`. -+2. `Curl_creader_will_rewind(data)`: tells if the reader chain rewinds at the start of the next request. -+3. `Curl_creader_set_rewind(data, TRUE)`: marks the reader chain for rewinding at the start of the next request. -+4. `Curl_client_start(data)`: tells the readers that a new request starts and they need to rewind if requested. -+ -+ -+## Summary and Outlook -+ -+By adding the client reader interface, any protocol can control how/if it wants the curl transfer to send bytes for a request. The transfer loop becomes then blissfully ignorant of the specifics. -+ -+The protocols on the other hand no longer have to care to package data most efficiently. At any time, should more data be needed, it can be read from the client. This is used when sending HTTP requests headers to add as much request body data to the initial sending as there is room for. -+ -+Future enhancements based on the client readers: -+* `expect-100` handling: place that into a HTTP specific reader at `CURL_CR_PROTOCOL` and eliminate the checks in the generic transfer parts. -+* `eos forwarding`: transfer should forward an `eos` flag to the connection filters. Filters like HTTP/2 and HTTP/3 can make use of that, terminating streams early. This would also eliminate length checks in stream handling. -diff --git a/docs/internals/CLIENT-WRITERS.md b/docs/internals/CLIENT-WRITERS.md -new file mode 100644 -index 000000000..9f7197d22 ---- /dev/null -+++ b/docs/internals/CLIENT-WRITERS.md -@@ -0,0 +1,123 @@ -+ -+ -+# curl client writers -+ -+Client writers is a design in the internals of libcurl, not visible in its public API. They were started -+in curl v8.5.0. This document describes the concepts, its high level implementation and the motivations. -+ -+## Naming -+ -+`libcurl` operates between clients and servers. A *client* is the application using libcurl, like the command line tool `curl` itself. Data to be uploaded to a server is **read** from the client and **send** to the server, the servers response is **received** by `libcurl` and then **written** to the client. -+ -+With this naming established, client writers are concerned with writing responses from the server to the application. Applications register callbacks via `CURLOPT_WRITEFUNCTION` and `CURLOPT_HEADERFUNCTION` to be invoked by `libcurl` when the response is received. -+ -+## Invoking -+ -+All code in `libcurl` that handles response data is ultimately expected to forward this data via `Curl_client_write()` to the application. The exact prototype of this function is: -+ -+``` -+CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *buf, size_t blen); -+``` -+The `type` argument specifies what the bytes in `buf` actually are. The following bits are defined: -+ -+``` -+#define CLIENTWRITE_BODY (1<<0) /* non-meta information, BODY */ -+#define CLIENTWRITE_INFO (1<<1) /* meta information, not a HEADER */ -+#define CLIENTWRITE_HEADER (1<<2) /* meta information, HEADER */ -+#define CLIENTWRITE_STATUS (1<<3) /* a special status HEADER */ -+#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */ -+#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ -+#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ -+``` -+ -+The main types here are `CLIENTWRITE_BODY` and `CLIENTWRITE_HEADER`. They are -+mutually exclusive. The other bits are enhancements to `CLIENTWRITE_HEADER` to -+specify what the header is about. They are only used in HTTP and related -+protocols (RTSP and WebSocket). -+ -+The implementation of `Curl_client_write()` uses a chain of *client writer* instances to process the call and make sure that the bytes reach the proper application callbacks. This is similar to the design of connection filters: client writers can be chained to process the bytes written through them. The definition is: -+ -+``` -+struct Curl_cwtype { -+ const char *name; -+ CURLcode (*do_init)(struct Curl_easy *data, -+ struct Curl_cwriter *writer); -+ CURLcode (*do_write)(struct Curl_easy *data, -+ struct Curl_cwriter *writer, int type, -+ const char *buf, size_t nbytes); -+ void (*do_close)(struct Curl_easy *data, -+ struct Curl_cwriter *writer); -+}; -+ -+struct Curl_cwriter { -+ const struct Curl_cwtype *cwt; /* type implementation */ -+ struct Curl_cwriter *next; /* Downstream writer. */ -+ Curl_cwriter_phase phase; /* phase at which it operates */ -+}; -+``` -+ -+`Curl_cwriter` is a writer instance with a `next` pointer to form the chain. It has a type `cwt` which provides the implementation. The main callback is `do_write()` that processes the data and calls then the `next` writer. The others are for setup and tear down. -+ -+## Phases and Ordering -+ -+Since client writers may transform the bytes written through them, the order in which the are called is relevant for the outcome. When a writer is created, one property it gets is the `phase` in which it operates. Writer phases are defined like: -+ -+``` -+typedef enum { -+ CURL_CW_RAW, /* raw data written, before any decoding */ -+ CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */ -+ CURL_CW_PROTOCOL, /* after transfer, but before content decoding */ -+ CURL_CW_CONTENT_DECODE, /* remove content-encodings */ -+ CURL_CW_CLIENT /* data written to client */ -+} Curl_cwriter_phase; -+``` -+ -+If a writer for phase `PROTOCOL` is added to the chain, it is always added *after* any `RAW` or `TRANSFER_DECODE` and *before* any `CONTENT_DECODE` and `CLIENT` phase writer. If there is already a writer for the same phase present, the new writer is inserted just before that one. -+ -+All transfers have a chain of 3 writers by default. A specific protocol handler may alter that by adding additional writers. The 3 standard writers are (name, phase): -+ -+1. `"raw", CURL_CW_RAW `: if the transfer is verbose, it forwards the body data to the debug function. -+1. `"download", CURL_CW_PROTOCOL`: checks that protocol limits are kept and updates progress counters. When a download has a known length, it checks that it is not exceeded and errors otherwise. -+1. `"client", CURL_CW_CLIENT`: the main work horse. It invokes the application callbacks or writes to the configured file handles. It chops large writes into smaller parts, as documented for `CURLOPT_WRITEFUNCTION`. If also handles *pausing* of transfers when the application callback returns `CURL_WRITEFUNC_PAUSE`. -+ -+With these writers always in place, libcurl's protocol handlers automatically have these implemented. -+ -+## Enhanced Use -+ -+HTTP is the protocol in curl that makes use of the client writer chain by -+adding writers to it. When the `libcurl` application set -+`CURLOPT_ACCEPT_ENCODING` (as `curl` does with `--compressed`), the server is -+offered an `Accept-Encoding` header with the algorithms supported. The server -+then may choose to send the response body compressed. For example using `gzip` -+or `brotli` or even both. -+ -+In the server's response, if there is a `Content-Encoding` header listing the -+encoding applied. If supported by `libcurl` it then decompresses the content -+before writing it out to the client. How does it do that? -+ -+The HTTP protocol adds client writers in phase `CURL_CW_CONTENT_DECODE` on -+seeing such a header. For each encoding listed, it adds the corresponding -+writer. The response from the server is then passed through -+`Curl_client_write()` to the writers that decode it. If several encodings had -+been applied the writer chain decodes them in the proper order. -+ -+When the server provides a `Content-Length` header, that value applies to the -+*compressed* content. Length checks on the response bytes must happen *before* -+it gets decoded. That is why this check happens in phase `CURL_CW_PROTOCOL` -+which always is ordered before writers in phase `CURL_CW_CONTENT_DECODE`. -+ -+What else? -+ -+Well, HTTP servers may also apply a `Transfer-Encoding` to the body of a response. The most well-known one is `chunked`, but algorithms like `gzip` and friends could also be applied. The difference to content encodings is that decoding needs to happen *before* protocol checks, for example on length, are done. -+ -+That is why transfer decoding writers are added for phase `CURL_CW_TRANSFER_DECODE`. Which makes their operation happen *before* phase `CURL_CW_PROTOCOL` where length may be checked. -+ -+## Summary -+ -+By adding the common behavior of all protocols into `Curl_client_write()` we make sure that they do apply everywhere. Protocol handler have less to worry about. Changes to default behavior can be done without affecting handler implementations. -+ -+Having a writer chain as implementation allows protocol handlers with extra needs, like HTTP, to add to this for special behavior. The common way of writing the actual response data stays the same. -diff --git a/docs/internals/CODE_STYLE.md b/docs/internals/CODE_STYLE.md -new file mode 100644 -index 000000000..f64c5eb7d ---- /dev/null -+++ b/docs/internals/CODE_STYLE.md -@@ -0,0 +1,316 @@ -+ -+ -+# curl C code style -+ -+Source code that has a common style is easier to read than code that uses -+different styles in different places. It helps making the code feel like one -+single code base. Easy-to-read is an important property of code and helps -+making it easier to review when new things are added and it helps debugging -+code when developers are trying to figure out why things go wrong. A unified -+style is more important than individual contributors having their own personal -+tastes satisfied. -+ -+Our C code has a few style rules. Most of them are verified and upheld by the -+`scripts/checksrc.pl` script. Invoked with `make checksrc` or even by default -+by the build system when built after `./configure --enable-debug` has been -+used. -+ -+It is normally not a problem for anyone to follow the guidelines, as you just -+need to copy the style already used in the source code and there are no -+particularly unusual rules in our set of rules. -+ -+We also work hard on writing code that are warning-free on all the major -+platforms and in general on as many platforms as possible. Code that obviously -+causes warnings is not accepted as-is. -+ -+## Naming -+ -+Try using a non-confusing naming scheme for your new functions and variable -+names. It does not necessarily have to mean that you should use the same as in -+other places of the code, just that the names should be logical, -+understandable and be named according to what they are used for. File-local -+functions should be made static. We like lower case names. -+ -+See the [INTERNALS](https://curl.se/dev/internals.html#symbols) document on -+how we name non-exported library-global symbols. -+ -+## Indenting -+ -+We use only spaces for indentation, never TABs. We use two spaces for each new -+open brace. -+ -+```c -+if(something_is_true) { -+ while(second_statement == fine) { -+ moo(); -+ } -+} -+``` -+ -+## Comments -+ -+Since we write C89 code, **//** comments are not allowed. They were not -+introduced in the C standard until C99. We use only __/* comments */__. -+ -+```c -+/* this is a comment */ -+``` -+ -+## Long lines -+ -+Source code in curl may never be wider than 79 columns and there are two -+reasons for maintaining this even in the modern era of large and high -+resolution screens: -+ -+1. Narrower columns are easier to read than wide ones. There is a reason -+ newspapers have used columns for decades or centuries. -+ -+2. Narrower columns allow developers to easier show multiple pieces of code -+ next to each other in different windows. It allows two or three source -+ code windows next to each other on the same screen - as well as multiple -+ terminal and debugging windows. -+ -+## Braces -+ -+In if/while/do/for expressions, we write the open brace on the same line as -+the keyword and we then set the closing brace on the same indentation level as -+the initial keyword. Like this: -+ -+```c -+if(age < 40) { -+ /* clearly a youngster */ -+} -+``` -+ -+You may omit the braces if they would contain only a one-line statement: -+ -+```c -+if(!x) -+ continue; -+``` -+ -+For functions the opening brace should be on a separate line: -+ -+```c -+int main(int argc, char **argv) -+{ -+ return 1; -+} -+``` -+ -+## 'else' on the following line -+ -+When adding an **else** clause to a conditional expression using braces, we -+add it on a new line after the closing brace. Like this: -+ -+```c -+if(age < 40) { -+ /* clearly a youngster */ -+} -+else { -+ /* probably grumpy */ -+} -+``` -+ -+## No space before parentheses -+ -+When writing expressions using if/while/do/for, there shall be no space -+between the keyword and the open parenthesis. Like this: -+ -+```c -+while(1) { -+ /* loop forever */ -+} -+``` -+ -+## Use boolean conditions -+ -+Rather than test a conditional value such as a bool against TRUE or FALSE, a -+pointer against NULL or != NULL and an int against zero or not zero in -+if/while conditions we prefer: -+ -+```c -+result = do_something(); -+if(!result) { -+ /* something went wrong */ -+ return result; -+} -+``` -+ -+## No assignments in conditions -+ -+To increase readability and reduce complexity of conditionals, we avoid -+assigning variables within if/while conditions. We frown upon this style: -+ -+```c -+if((ptr = malloc(100)) == NULL) -+ return NULL; -+``` -+ -+and instead we encourage the above version to be spelled out more clearly: -+ -+```c -+ptr = malloc(100); -+if(!ptr) -+ return NULL; -+``` -+ -+## New block on a new line -+ -+We never write multiple statements on the same source line, even for short -+if() conditions. -+ -+```c -+if(a) -+ return TRUE; -+else if(b) -+ return FALSE; -+``` -+ -+and NEVER: -+ -+```c -+if(a) return TRUE; -+else if(b) return FALSE; -+``` -+ -+## Space around operators -+ -+Please use spaces on both sides of operators in C expressions. Postfix **(), -+[], ->, ., ++, --** and Unary **+, -, !, ~, &** operators excluded they should -+have no space. -+ -+Examples: -+ -+```c -+bla = func(); -+who = name[0]; -+age += 1; -+true = !false; -+size += -2 + 3 * (a + b); -+ptr->member = a++; -+struct.field = b--; -+ptr = &address; -+contents = *pointer; -+complement = ~bits; -+empty = (!*string) ? TRUE : FALSE; -+``` -+ -+## No parentheses for return values -+ -+We use the 'return' statement without extra parentheses around the value: -+ -+```c -+int works(void) -+{ -+ return TRUE; -+} -+``` -+ -+## Parentheses for sizeof arguments -+ -+When using the sizeof operator in code, we prefer it to be written with -+parentheses around its argument: -+ -+```c -+int size = sizeof(int); -+``` -+ -+## Column alignment -+ -+Some statements cannot be completed on a single line because the line would be -+too long, the statement too hard to read, or due to other style guidelines -+above. In such a case the statement spans multiple lines. -+ -+If a continuation line is part of an expression or sub-expression then you -+should align on the appropriate column so that it is easy to tell what part of -+the statement it is. Operators should not start continuation lines. In other -+cases follow the 2-space indent guideline. Here are some examples from -+libcurl: -+ -+```c -+if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && -+ (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && -+ (handle->set.httpreq == HTTPREQ_GET || -+ handle->set.httpreq == HTTPREQ_HEAD)) -+ /* did not ask for HTTP/1.0 and a GET or HEAD */ -+ return TRUE; -+``` -+ -+If no parenthesis, use the default indent: -+ -+```c -+data->set.http_disable_hostname_check_before_authentication = -+ (0 != va_arg(param, long)) ? TRUE : FALSE; -+``` -+ -+Function invoke with an open parenthesis: -+ -+```c -+if(option) { -+ result = parse_login_details(option, strlen(option), -+ (userp ? &user : NULL), -+ (passwdp ? &passwd : NULL), -+ NULL); -+} -+``` -+ -+Align with the "current open" parenthesis: -+ -+```c -+DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " -+ "server response left\n", -+ (int)clipamount)); -+``` -+ -+## Platform dependent code -+ -+Use **#ifdef HAVE_FEATURE** to do conditional code. We avoid checking for -+particular operating systems or hardware in the #ifdef lines. The HAVE_FEATURE -+shall be generated by the configure script for Unix-like systems and they are -+hard-coded in the `config-[system].h` files for the others. -+ -+We also encourage use of macros/functions that possibly are empty or defined -+to constants when libcurl is built without that feature, to make the code -+seamless. Like this example where the **magic()** function works differently -+depending on a build-time conditional: -+ -+```c -+#ifdef HAVE_MAGIC -+void magic(int a) -+{ -+ return a + 2; -+} -+#else -+#define magic(x) 1 -+#endif -+ -+int content = magic(3); -+``` -+ -+## No typedefed structs -+ -+Use structs by all means, but do not typedef them. Use the `struct name` way -+of identifying them: -+ -+```c -+struct something { -+ void *valid; -+ size_t way_to_write; -+}; -+struct something instance; -+``` -+ -+**Not okay**: -+ -+```c -+typedef struct { -+ void *wrong; -+ size_t way_to_write; -+} something; -+something instance; -+``` -diff --git a/docs/internals/CONNECTION-FILTERS.md b/docs/internals/CONNECTION-FILTERS.md -new file mode 100644 -index 000000000..629e769b9 ---- /dev/null -+++ b/docs/internals/CONNECTION-FILTERS.md -@@ -0,0 +1,308 @@ -+ -+ -+# curl connection filters -+ -+Connection filters is a design in the internals of curl, not visible in its -+public API. They were added in curl v7.87.0. This document describes the -+concepts, its high level implementation and the motivations. -+ -+## Filters -+ -+A "connection filter" is a piece of code that is responsible for handling a -+range of operations of curl's connections: reading, writing, waiting on -+external events, connecting and closing down - to name the most important -+ones. -+ -+The most important feat of connection filters is that they can be stacked on -+top of each other (or "chained" if you prefer that metaphor). In the common -+scenario that you want to retrieve a `https:` URL with curl, you need 2 basic -+things to send the request and get the response: a TCP connection, represented -+by a `socket` and a SSL instance en- and decrypt over that socket. You write -+your request to the SSL instance, which encrypts and writes that data to the -+socket, which then sends the bytes over the network. -+ -+With connection filters, curl's internal setup looks something like this (cf -+for connection filter): -+ -+``` -+Curl_easy *data connectdata *conn cf-ssl cf-socket -++----------------+ +-----------------+ +-------+ +--------+ -+|https://curl.se/|----> | properties |----> | keys |---> | socket |--> OS --> network -++----------------+ +-----------------+ +-------+ +--------+ -+ -+ Curl_write(data, buffer) -+ --> Curl_cfilter_write(data, data->conn, buffer) -+ ---> conn->filter->write(conn->filter, data, buffer) -+``` -+ -+While connection filters all do different things, they look the same from the -+"outside". The code in `data` and `conn` does not really know **which** -+filters are installed. `conn` just writes into the first filter, whatever that -+is. -+ -+Same is true for filters. Each filter has a pointer to the `next` filter. When -+SSL has encrypted the data, it does not write to a socket, it writes to the -+next filter. If that is indeed a socket, or a file, or an HTTP/2 connection is -+of no concern to the SSL filter. -+ -+This allows stacking, as in: -+ -+``` -+Direct: -+ http://localhost/ conn -> cf-socket -+ https://curl.se/ conn -> cf-ssl -> cf-socket -+Via http proxy tunnel: -+ http://localhost/ conn -> cf-http-proxy -> cf-socket -+ https://curl.se/ conn -> cf-ssl -> cf-http-proxy -> cf-socket -+Via https proxy tunnel: -+ http://localhost/ conn -> cf-http-proxy -> cf-ssl -> cf-socket -+ https://curl.se/ conn -> cf-ssl -> cf-http-proxy -> cf-ssl -> cf-socket -+Via http proxy tunnel via SOCKS proxy: -+ http://localhost/ conn -> cf-http-proxy -> cf-socks -> cf-socket -+``` -+ -+### Connecting/Closing -+ -+Before `Curl_easy` can send the request, the connection needs to be -+established. This means that all connection filters have done, whatever they -+need to do: waiting for the socket to be connected, doing the TLS handshake, -+performing the HTTP tunnel request, etc. This has to be done in reverse order: -+the last filter has to do its connect first, then the one above can start, -+etc. -+ -+Each filter does in principle the following: -+ -+``` -+static CURLcode -+myfilter_cf_connect(struct Curl_cfilter *cf, -+ struct Curl_easy *data, -+ bool *done) -+{ -+ CURLcode result; -+ -+ if(cf->connected) { /* we and all below are done */ -+ *done = TRUE; -+ return CURLE_OK; -+ } -+ /* Let the filters below connect */ -+ result = cf->next->cft->connect(cf->next, data, blocking, done); -+ if(result || !*done) -+ return result; /* below errored/not finished yet */ -+ -+ /* MYFILTER CONNECT THINGS */ /* below connected, do out thing */ -+ *done = cf->connected = TRUE; /* done, remember, return */ -+ return CURLE_OK; -+} -+``` -+ -+Closing a connection then works similar. The `conn` tells the first filter to -+close. Contrary to connecting, the filter does its own things first, before -+telling the next filter to close. -+ -+### Efficiency -+ -+There are two things curl is concerned about: efficient memory use and fast -+transfers. -+ -+The memory footprint of a filter is relatively small: -+ -+``` -+struct Curl_cfilter { -+ const struct Curl_cftype *cft; /* the type providing implementation */ -+ struct Curl_cfilter *next; /* next filter in chain */ -+ void *ctx; /* filter type specific settings */ -+ struct connectdata *conn; /* the connection this filter belongs to */ -+ int sockindex; /* TODO: like to get rid off this */ -+ BIT(connected); /* != 0 iff this filter is connected */ -+}; -+``` -+ -+The filter type `cft` is a singleton, one static struct for each type of -+filter. The `ctx` is where a filter holds its specific data. That varies by -+filter type. An http-proxy filter keeps the ongoing state of the CONNECT here, -+free it after its has been established. The SSL filter keeps the `SSL*` (if -+OpenSSL is used) here until the connection is closed. So, this varies. -+ -+`conn` is a reference to the connection this filter belongs to, so nothing -+extra besides the pointer itself. -+ -+Several things, that before were kept in `struct connectdata`, now goes into -+the `filter->ctx` *when needed*. So, the memory footprint for connections that -+do *not* use an http proxy, or socks, or https is lower. -+ -+As to transfer efficiency, writing and reading through a filter comes at near -+zero cost *if the filter does not transform the data*. An http proxy or socks -+filter, once it is connected, just passes the calls through. Those filters -+implementations look like this: -+ -+``` -+ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, -+ const void *buf, size_t len, CURLcode *err) -+{ -+ return cf->next->cft->do_send(cf->next, data, buf, len, err); -+} -+``` -+The `recv` implementation is equivalent. -+ -+## Filter Types -+ -+The currently existing filter types (curl 8.5.0) are: -+ -+* `TCP`, `UDP`, `UNIX`: filters that operate on a socket, providing raw I/O. -+* `SOCKET-ACCEPT`: special TCP socket that has a socket that has been -+ `accept()`ed in a `listen()` -+* `SSL`: filter that applies TLS en-/decryption and handshake. Manages the -+ underlying TLS backend implementation. -+* `HTTP-PROXY`, `H1-PROXY`, `H2-PROXY`: the first manages the connection to an -+ HTTP proxy server and uses the other depending on which ALPN protocol has -+ been negotiated. -+* `SOCKS-PROXY`: filter for the various SOCKS proxy protocol variations -+* `HAPROXY`: filter for the protocol of the same name, providing client IP -+ information to a server. -+* `HTTP/2`: filter for handling multiplexed transfers over an HTTP/2 -+ connection -+* `HTTP/3`: filter for handling multiplexed transfers over an HTTP/3+QUIC -+ connection -+* `HAPPY-EYEBALLS`: meta filter that implements IPv4/IPv6 "happy eyeballing". -+ It creates up to 2 sub-filters that race each other for a connection. -+* `SETUP`: meta filter that manages the creation of sub-filter chains for a -+ specific transport (e.g. TCP or QUIC). -+* `HTTPS-CONNECT`: meta filter that races a TCP+TLS and a QUIC connection -+ against each other to determine if HTTP/1.1, HTTP/2 or HTTP/3 shall be used -+ for a transfer. -+ -+Meta filters are combining other filters for a specific purpose, mostly during -+connection establishment. Other filters like `TCP`, `UDP` and `UNIX` are only -+to be found at the end of filter chains. SSL filters provide encryption, of -+course. Protocol filters change the bytes sent and received. -+ -+## Filter Flags -+ -+Filter types carry flags that inform what they do. These are (for now): -+ -+* `CF_TYPE_IP_CONNECT`: this filter type talks directly to a server. This does -+ not have to be the server the transfer wants to talk to. For example when a -+ proxy server is used. -+* `CF_TYPE_SSL`: this filter type provides encryption. -+* `CF_TYPE_MULTIPLEX`: this filter type can manage multiple transfers in parallel. -+ -+Filter types can combine these flags. For example, the HTTP/3 filter types -+have `CF_TYPE_IP_CONNECT`, `CF_TYPE_SSL` and `CF_TYPE_MULTIPLEX` set. -+ -+Flags are useful to extrapolate properties of a connection. To check if a -+connection is encrypted, libcurl inspect the filter chain in place, top down, -+for `CF_TYPE_SSL`. If it finds `CF_TYPE_IP_CONNECT` before any `CF_TYPE_SSL`, -+the connection is not encrypted. -+ -+For example, `conn1` is for a `http:` request using a tunnel through an HTTP/2 -+`https:` proxy. `conn2` is a `https:` HTTP/2 connection to the same proxy. -+`conn3` uses HTTP/3 without proxy. The filter chains would look like this -+(simplified): -+ -+``` -+conn1 --> `HTTP-PROXY` --> `H2-PROXY` --> `SSL` --> `TCP` -+flags: `IP_CONNECT` `SSL` `IP_CONNECT` -+ -+conn2 --> `HTTP/2` --> `SSL` --> `HTTP-PROXY` --> `H2-PROXY` --> `SSL` --> `TCP` -+flags: `SSL` `IP_CONNECT` `SSL` `IP_CONNECT` -+ -+conn3 --> `HTTP/3` -+flags: `SSL|IP_CONNECT` -+``` -+ -+Inspecting the filter chains, `conn1` is seen as unencrypted, since it -+contains an `IP_CONNECT` filter before any `SSL`. `conn2` is clearly encrypted -+as an `SSL` flagged filter is seen first. `conn3` is also encrypted as the -+`SSL` flag is checked before the presence of `IP_CONNECT`. -+ -+Similar checks can determine if a connection is multiplexed or not. -+ -+## Filter Tracing -+ -+Filters may make use of special trace macros like `CURL_TRC_CF(data, cf, msg, -+...)`. With `data` being the transfer and `cf` being the filter instance. -+These traces are normally not active and their execution is guarded so that -+they are cheap to ignore. -+ -+Users of `curl` may activate them by adding the name of the filter type to the -+`--trace-config` argument. For example, in order to get more detailed tracing -+of an HTTP/2 request, invoke curl with: -+ -+``` -+> curl -v --trace-config ids,time,http/2 https://curl.se -+``` -+ -+Which gives you trace output with time information, transfer+connection ids -+and details from the `HTTP/2` filter. Filter type names in the trace config -+are case insensitive. You may use `all` to enable tracing for all filter -+types. When using `libcurl` you may call `curl_global_trace(config_string)` at -+the start of your application to enable filter details. -+ -+## Meta Filters -+ -+Meta filters is a catch-all name for filter types that do not change the -+transfer data in any way but provide other important services to curl. In -+general, it is possible to do all sorts of silly things with them. One of the -+commonly used, important things is "eyeballing". -+ -+The `HAPPY-EYEBALLS` filter is involved in the connect phase. Its job is to -+try the various IPv4 and IPv6 addresses that are known for a server. If only -+one address family is known (or configured), it tries the addresses one after -+the other with timeouts calculated from the amount of addresses and the -+overall connect timeout. -+ -+When more than one address family is to be tried, it splits the address list -+into IPv4 and IPv6 and makes parallel attempts. The connection filter chain -+looks like this: -+ -+``` -+* create connection for http://curl.se -+conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> NULL -+* start connect -+conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> NULL -+ - ballerv4 --> TCP[151.101.1.91]:443 -+ - ballerv6 --> TCP[2a04:4e42:c00::347]:443 -+* v6 answers, connected -+conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> TCP[2a04:4e42:c00::347]:443 -+* transfer -+``` -+ -+The modular design of connection filters and that we can plug them into each other is used to control the parallel attempts. When a `TCP` filter does not connect (in time), it is torn down and another one is created for the next address. This keeps the `TCP` filter simple. -+ -+The `HAPPY-EYEBALLS` on the other hand stays focused on its side of the problem. We can use it also to make other type of connection by just giving it another filter type to try to have happy eyeballing for QUIC: -+ -+``` -+* create connection for --http3-only https://curl.se -+conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL -+* start connect -+conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL -+ - ballerv4 --> HTTP/3[151.101.1.91]:443 -+ - ballerv6 --> HTTP/3[2a04:4e42:c00::347]:443 -+* v6 answers, connected -+conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> HTTP/3[2a04:4e42:c00::347]:443 -+* transfer -+``` -+ -+When we plug these two variants together, we get the `HTTPS-CONNECT` filter -+type that is used for `--http3` when **both** HTTP/3 and HTTP/2 or HTTP/1.1 -+shall be attempted: -+ -+``` -+* create connection for --http3 https://curl.se -+conn[curl.se] --> HTTPS-CONNECT --> NULL -+* start connect -+conn[curl.se] --> HTTPS-CONNECT --> NULL -+ - SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL -+ - ballerv4 --> HTTP/3[151.101.1.91]:443 -+ - ballerv6 --> HTTP/3[2a04:4e42:c00::347]:443 -+ - SETUP[TCP] --> HAPPY-EYEBALLS --> NULL -+ - ballerv4 --> TCP[151.101.1.91]:443 -+ - ballerv6 --> TCP[2a04:4e42:c00::347]:443 -+* v4 QUIC answers, connected -+conn[curl.se] --> HTTPS-CONNECT --> SETUP[QUIC] --> HAPPY-EYEBALLS --> HTTP/3[151.101.1.91]:443 -+* transfer -+``` -diff --git a/docs/internals/DYNBUF.md b/docs/internals/DYNBUF.md -new file mode 100644 -index 000000000..01fe332ab ---- /dev/null -+++ b/docs/internals/DYNBUF.md -@@ -0,0 +1,134 @@ -+ -+ -+# dynbuf -+ -+This is the internal module for creating and handling "dynamic buffers". This -+means buffers that can be appended to, dynamically and grow to adapt. -+ -+There is always a terminating zero put at the end of the dynamic buffer. -+ -+The `struct dynbuf` is used to hold data for each instance of a dynamic -+buffer. The members of that struct **MUST NOT** be accessed or modified -+without using the dedicated dynbuf API. -+ -+## `Curl_dyn_init` -+ -+```c -+void Curl_dyn_init(struct dynbuf *s, size_t toobig); -+``` -+ -+This initializes a struct to use for dynbuf and it cannot fail. The `toobig` -+value **must** be set to the maximum size we allow this buffer instance to -+grow to. The functions below return `CURLE_OUT_OF_MEMORY` when hitting this -+limit. -+ -+## `Curl_dyn_free` -+ -+```c -+void Curl_dyn_free(struct dynbuf *s); -+``` -+ -+Free the associated memory and clean up. After a free, the `dynbuf` struct can -+be reused to start appending new data to. -+ -+## `Curl_dyn_addn` -+ -+```c -+CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len); -+``` -+ -+Append arbitrary data of a given length to the end of the buffer. -+ -+If this function fails it calls `Curl_dyn_free` on `dynbuf`. -+ -+## `Curl_dyn_add` -+ -+```c -+CURLcode Curl_dyn_add(struct dynbuf *s, const char *str); -+``` -+ -+Append a C string to the end of the buffer. -+ -+If this function fails it calls `Curl_dyn_free` on `dynbuf`. -+ -+## `Curl_dyn_addf` -+ -+```c -+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...); -+``` -+ -+Append a `printf()`-style string to the end of the buffer. -+ -+If this function fails it calls `Curl_dyn_free` on `dynbuf`. -+ -+## `Curl_dyn_vaddf` -+ -+```c -+CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap); -+``` -+ -+Append a `vprintf()`-style string to the end of the buffer. -+ -+If this function fails it calls `Curl_dyn_free` on `dynbuf`. -+ -+## `Curl_dyn_reset` -+ -+```c -+void Curl_dyn_reset(struct dynbuf *s); -+``` -+ -+Reset the buffer length, but leave the allocation. -+ -+## `Curl_dyn_tail` -+ -+```c -+CURLcode Curl_dyn_tail(struct dynbuf *s, size_t length); -+``` -+ -+Keep `length` bytes of the buffer tail (the last `length` bytes of the -+buffer). The rest of the buffer is dropped. The specified `length` must not be -+larger than the buffer length. To instead keep the leading part, see -+`Curl_dyn_setlen()`. -+ -+## `Curl_dyn_ptr` -+ -+```c -+char *Curl_dyn_ptr(const struct dynbuf *s); -+``` -+ -+Returns a `char *` to the buffer if it has a length, otherwise may return -+NULL. Since the buffer may be reallocated, this pointer should not be trusted -+or used anymore after the next buffer manipulation call. -+ -+## `Curl_dyn_uptr` -+ -+```c -+unsigned char *Curl_dyn_uptr(const struct dynbuf *s); -+``` -+ -+Returns an `unsigned char *` to the buffer if it has a length, otherwise may -+return NULL. Since the buffer may be reallocated, this pointer should not be -+trusted or used anymore after the next buffer manipulation call. -+ -+## `Curl_dyn_len` -+ -+```c -+size_t Curl_dyn_len(const struct dynbuf *s); -+``` -+ -+Returns the length of the buffer in bytes. Does not include the terminating -+zero byte. -+ -+## `Curl_dyn_setlen` -+ -+```c -+CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t len); -+``` -+ -+Sets the new shorter length of the buffer in number of bytes. Keeps the -+leftmost set number of bytes, discards the rest. To instead keep the tail part -+of the buffer, see `Curl_dyn_tail()`. -diff --git a/docs/internals/HASH.md b/docs/internals/HASH.md -new file mode 100644 -index 000000000..5a5bdc983 ---- /dev/null -+++ b/docs/internals/HASH.md -@@ -0,0 +1,188 @@ -+ -+ -+# `hash` -+ -+ #include "hash.h" -+ -+This is the internal module for doing hash tables. A hash table uses a hash -+function to compute an index. On each index there is a separate linked list of -+entries. -+ -+Create a hash table. Add items. Retrieve items. Remove items. Destroy table. -+ -+## `Curl_hash_init` -+ -+~~~c -+void Curl_hash_init(struct Curl_hash *h, -+ size_t slots, -+ hash_function hfunc, -+ comp_function comparator, -+ Curl_hash_dtor dtor); -+~~~ -+ -+The call initializes a `struct Curl_hash`. -+ -+- `slots` is the number of entries to create in the hash table. Larger is -+ better (faster lookups) but also uses more memory. -+- `hfunc` is a function pointer to a function that returns a `size_t` value as -+ a checksum for an entry in this hash table. Ideally, it returns a unique -+ value for every entry ever added to the hash table, but hash collisions are -+ handled. -+- `comparator` is a function pointer to a function that compares two hash -+ table entries. It should return non-zero if the compared items are -+ identical. -+- `dtor` is a function pointer to a destructor called when an entry is removed -+ from the table -+ -+## `Curl_hash_add` -+ -+~~~c -+void * -+Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p) -+~~~ -+ -+This call adds an entry to the hash. `key` points to the hash key and -+`key_len` is the length of the hash key. `p` is a custom pointer. -+ -+If there already was a match in the hash, that data is replaced with this new -+entry. -+ -+This function also lazily allocates the table if needed, as it is not done in -+the `Curl_hash_init` function. -+ -+Returns NULL on error, otherwise it returns a pointer to `p`. -+ -+## `Curl_hash_add2` -+ -+~~~c -+void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p, -+ Curl_hash_elem_dtor dtor) -+~~~ -+ -+This works like `Curl_hash_add` but has an extra argument: `dtor`, which is a -+destructor call for this specific entry. When this entry is removed, this -+function is called instead of the function stored for the whole hash table. -+ -+## `Curl_hash_delete` -+ -+~~~c -+int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len); -+~~~ -+ -+This function removes an entry from the hash table. If successful, it returns -+zero. If the entry was not found, it returns 1. -+ -+## `Curl_hash_pick` -+ -+~~~c -+void *Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len); -+~~~ -+ -+If there is an entry in the hash that matches the given `key` with size of -+`key_len`, that its custom pointer is returned. The pointer that was called -+`p` when the entry was added. -+ -+It returns NULL if there is no matching entry in the hash. -+ -+## `Curl_hash_destroy` -+ -+~~~c -+void Curl_hash_destroy(struct Curl_hash *h); -+~~~ -+ -+This function destroys a hash and cleanups up all its related data. Calling it -+multiple times is fine. -+ -+## `Curl_hash_clean` -+ -+~~~c -+void Curl_hash_clean(struct Curl_hash *h); -+~~~ -+ -+This function removes all the entries in the given hash. -+ -+## `Curl_hash_clean_with_criterium` -+ -+~~~c -+void -+Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, -+ int (*comp)(void *, void *)) -+~~~ -+ -+This function removes all the entries in the given hash that matches the -+criterion. The provided `comp` function determines if the criteria is met by -+returning non-zero. -+ -+## `Curl_hash_count` -+ -+~~~c -+size_t Curl_hash_count(struct Curl_hash *h) -+~~~ -+ -+Returns the number of entries stored in the hash. -+ -+## `Curl_hash_start_iterate` -+ -+~~~c -+void Curl_hash_start_iterate(struct Curl_hash *hash, -+ struct Curl_hash_iterator *iter): -+~~~ -+ -+This function initializes a `struct Curl_hash_iterator` that `iter` points to. -+It can then be used to iterate over all the entries in the hash. -+ -+## `Curl_hash_next_element` -+ -+~~~c -+struct Curl_hash_element * -+Curl_hash_next_element(struct Curl_hash_iterator *iter); -+~~~ -+ -+Given the iterator `iter`, this function returns a pointer to the next hash -+entry if there is one, or NULL if there is no more entries. -+ -+Called repeatedly, it iterates over all the entries in the hash table. -+ -+Note: it only guarantees functionality if the hash table remains untouched -+during its iteration. -+ -+# `curl_off_t` dedicated hash functions -+ -+## `Curl_hash_offt_init` -+ -+~~~c -+void Curl_hash_offt_init(struct Curl_hash *h, -+ size_t slots, -+ Curl_hash_dtor dtor); -+~~~ -+ -+Initializes a hash table for `curl_off_t` values. Pass in desired number of -+`slots` and `dtor` function. -+ -+## `Curl_hash_offt_set` -+ -+~~~c -+void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem); -+~~~ -+ -+Associate a custom `elem` pointer with the given `id`. -+ -+## `Curl_hash_offt_remove` -+ -+~~~c -+int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id); -+~~~ -+ -+Remove the `id` from the hash. -+ -+## `Curl_hash_offt_get` -+ -+~~~c -+void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id); -+~~~ -+ -+Get the pointer associated with the specified `id`. -diff --git a/docs/internals/HYPER.md b/docs/internals/HYPER.md -new file mode 100644 -index 000000000..bbaa4e4d5 ---- /dev/null -+++ b/docs/internals/HYPER.md -@@ -0,0 +1,78 @@ -+ -+ -+# Hyper -+ -+Hyper is a separate HTTP library written in Rust. curl can be told to use this -+library as a backend to deal with HTTP. -+ -+## EXPERIMENTAL -+ -+Hyper support in curl is considered **EXPERIMENTAL** until further notice. It -+needs to be explicitly enabled at build-time. -+ -+Further development and tweaking of the Hyper backend support in curl happens -+in the master branch using pull-requests, just like ordinary changes. -+ -+## Hyper version -+ -+The C API for Hyper is brand new and is still under development. -+ -+## Build curl with hyper -+ -+Using Rust 1.64.0 or later, build hyper and enable its C API like this: -+ -+ % git clone https://github.com/hyperium/hyper -+ % cd hyper -+ % RUSTFLAGS="--cfg hyper_unstable_ffi" cargo rustc --features client,http1,http2,ffi --crate-type cdylib -+ -+Also, `--release` can be added for a release (optimized) build. -+ -+Build curl to use hyper's C API: -+ -+ % git clone https://github.com/curl/curl -+ % cd curl -+ % autoreconf -fi -+ % ./configure LDFLAGS="-Wl,-rpath,/target/debug -Wl,-rpath,/target/release" --with-openssl --with-hyper= -+ % make -+ -+# Using Hyper internally -+ -+Hyper is a low level HTTP transport library. curl itself provides all HTTP -+headers and Hyper provides all received headers back to curl. -+ -+Therefore, most of the "header logic" in curl as in responding to and acting -+on specific input and output headers are done the same way in curl code. -+ -+The API in Hyper delivers received HTTP headers as (cleaned up) name=value -+pairs, making it impossible for curl to know the exact byte representation -+over the wire with Hyper. -+ -+## Limitations -+ -+The hyper backend does not support -+ -+- `CURLOPT_IGNORE_CONTENT_LENGTH` -+- `--raw` and disabling `CURLOPT_HTTP_TRANSFER_DECODING` -+- RTSP -+- hyper is much stricter about what HTTP header contents it allows -+- leading whitespace in first HTTP/1 response header -+- HTTP/0.9 -+- HTTP/2 upgrade using HTTP:// URLs. Aka 'h2c' -+- HTTP/2 in general. Hyper has support for HTTP/2 but the curl side -+ needs changes so that a `hyper_clientconn` can last for the duration -+ of a connection. Probably this means turning the Hyper HTTP/2 backend -+ into a connection filter. -+ -+## Remaining issues -+ -+This backend is still not feature complete with the native backend. Areas that -+still need attention and verification include: -+ -+- multiplexed HTTP/2 -+- h2 Upgrade: -+- receiving HTTP/1 trailers -+- sending HTTP/1 trailers -diff --git a/docs/internals/LLIST.md b/docs/internals/LLIST.md -new file mode 100644 -index 000000000..ee9a89bad ---- /dev/null -+++ b/docs/internals/LLIST.md -@@ -0,0 +1,190 @@ -+ -+ -+# `llist` - linked lists -+ -+ #include "llist.h" -+ -+This is the internal module for linked lists. The API is designed to be -+flexible but also to avoid dynamic memory allocation. -+ -+None of the involved structs should be accessed using struct fields (outside -+of `llist.c`). Use the functions. -+ -+## Setup and shutdown -+ -+`struct Curl_llist` is the struct holding a single linked list. It needs to be -+initialized with a call to `Curl_llist_init()` before it can be used -+ -+To clean up a list, call `Curl_llist_destroy()`. Since the linked lists -+themselves do not allocate memory, it can also be fine to just *not* clean up -+the list. -+ -+## Add a node -+ -+There are two functions for adding a node to a linked list: -+ -+1. Add it last in the list with `Curl_llist_append` -+2. Add it after a specific existing node with `Curl_llist_insert_next` -+ -+When a node is added to a list, it stores an associated custom pointer to -+anything you like and you provide a pointer to a `struct Curl_llist_node` -+struct in which it stores and updates pointers. If you intend to add the same -+struct to multiple lists concurrently, you need to have one `struct -+Curl_llist_node` for each list. -+ -+Add a node to a list with `Curl_llist_append(list, elem, node)`. Where -+ -+- `list`: points to a `struct Curl_llist` -+- `elem`: points to what you want added to the list -+- `node`: is a pointer to a `struct Curl_llist_node`. Data storage for this -+ node. -+ -+Example: to add a `struct foobar` to a linked list. Add a node struct within -+it: -+ -+ struct foobar { -+ char *random; -+ struct Curl_llist_node storage; /* can be anywhere in the struct */ -+ char *data; -+ }; -+ -+ struct Curl_llist barlist; /* the list for foobar entries */ -+ struct foobar entries[10]; -+ -+ Curl_llist_init(&barlist, NULL); -+ -+ /* add the first struct to the list */ -+ Curl_llist_append(&barlist, &entries[0], &entries[0].storage); -+ -+See also `Curl_llist_insert_next`. -+ -+## Remove a node -+ -+Remove a node again from a list by calling `Curl_llist_remove()`. -+ -+## Iterate -+ -+To iterate over a list: first get the head entry and then iterate over the -+nodes as long there is a next. Each node has an *element* associated with it, -+the custom pointer you stored there. Usually a struct pointer or similar. -+ -+ struct Curl_llist_node *iter; -+ -+ /* get the first entry of the 'barlist' */ -+ iter = Curl_llist_head(&barlist); -+ -+ while(iter) { -+ /* extract the element pointer from the node */ -+ struct foobar *elem = Curl_node_elem(iter); -+ -+ /* advance to the next node in the list */ -+ iter = Curl_node_next(iter); -+ } -+ -+# Function overview -+ -+## `Curl_llist_init` -+ -+~~~c -+void Curl_llist_init(struct Curl_llist *list, Curl_llist_dtor dtor); -+~~~ -+ -+Initializes the `list`. The argument `dtor` is NULL or a function pointer that -+gets called when list nodes are removed from this list. -+ -+The function is infallible. -+ -+~~~c -+typedef void (*Curl_llist_dtor)(void *user, void *elem); -+~~~ -+ -+`dtor` is called with two arguments: `user` and `elem`. The first being the -+`user` pointer passed in to `Curl_llist_remove()`or `Curl_llist_destroy()` and -+the second is the `elem` pointer associated with removed node. The pointer -+that `Curl_node_elem()` would have returned for that node. -+ -+## `Curl_llist_destroy` -+ -+~~~c -+void Curl_llist_destroy(struct Curl_llist *list, void *user); -+~~~ -+ -+This removes all nodes from the `list`. This leaves the list in a cleared -+state. -+ -+The function is infallible. -+ -+## `Curl_llist_append` -+ -+~~~c -+void Curl_llist_append(struct Curl_llist *list, -+ const void *elem, struct Curl_llist_node *node); -+~~~ -+ -+Adds `node` last in the `list` with a custom pointer to `elem`. -+ -+The function is infallible. -+ -+## `Curl_llist_insert_next` -+ -+~~~c -+void Curl_llist_insert_next(struct Curl_llist *list, -+ struct Curl_llist_node *node, -+ const void *elem, -+ struct Curl_llist_node *node); -+~~~ -+ -+Adds `node` to the `list` with a custom pointer to `elem` immediately after -+the previous list `node`. -+ -+The function is infallible. -+ -+## `Curl_llist_head` -+ -+~~~c -+struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list); -+~~~ -+ -+Returns a pointer to the first node of the `list`, or a NULL if empty. -+ -+## `Curl_node_uremove` -+ -+~~~c -+void Curl_node_uremove(struct Curl_llist_node *node, void *user); -+~~~ -+ -+Removes the `node` the list it was previously added to. Passes the `user` -+pointer to the list's destructor function if one was setup. -+ -+The function is infallible. -+ -+## `Curl_node_remove` -+ -+~~~c -+void Curl_node_remove(struct Curl_llist_node *node); -+~~~ -+ -+Removes the `node` the list it was previously added to. Passes a NULL pointer -+to the list's destructor function if one was setup. -+ -+The function is infallible. -+ -+## `Curl_node_elem` -+ -+~~~c -+void *Curl_node_elem(struct Curl_llist_node *node); -+~~~ -+ -+Given a list node, this function returns the associated element. -+ -+## `Curl_node_next` -+ -+~~~c -+struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *node); -+~~~ -+ -+Given a list node, this function returns the next node in the list. -diff --git a/docs/internals/MQTT.md b/docs/internals/MQTT.md -new file mode 100644 -index 000000000..90d641b30 ---- /dev/null -+++ b/docs/internals/MQTT.md -@@ -0,0 +1,51 @@ -+ -+ -+# MQTT in curl -+ -+## Usage -+ -+A plain "GET" subscribes to the topic and prints all published messages. -+ -+Doing a "POST" publishes the post data to the topic and exits. -+ -+ -+### Subscribing -+ -+Command usage: -+ -+ curl mqtt://host/topic -+ -+Example subscribe: -+ -+ curl mqtt://host.home/bedroom/temp -+ -+This will send an MQTT SUBSCRIBE packet for the topic `bedroom/temp` and listen in for incoming PUBLISH packets. -+ -+### Publishing -+ -+Command usage: -+ -+ curl -d payload mqtt://host/topic -+ -+Example publish: -+ -+ curl -d 75 mqtt://host.home/bedroom/dimmer -+ -+This will send an MQTT PUBLISH packet to the topic `bedroom/dimmer` with the payload `75`. -+ -+## What does curl deliver as a response to a subscribe -+ -+Whenever a PUBLISH packet is received, curl outputs two bytes topic length (MSB | LSB), the topic followed by the -+payload. -+ -+## Caveats -+ -+Remaining limitations: -+ - Only QoS level 0 is implemented for publish -+ - No way to set retain flag for publish -+ - No TLS (mqtts) support -+ - Naive EAGAIN handling does not handle split messages -diff --git a/docs/internals/NEW-PROTOCOL.md b/docs/internals/NEW-PROTOCOL.md -new file mode 100644 -index 000000000..35beba6ed ---- /dev/null -+++ b/docs/internals/NEW-PROTOCOL.md -@@ -0,0 +1,116 @@ -+ -+ -+# Adding a new protocol? -+ -+Every once in a while, someone comes up with the idea of adding support for yet -+another protocol to curl. After all, curl already supports 25 something -+protocols and it is the Internet transfer machine for the world. -+ -+In the curl project we love protocols and we love supporting many protocols -+and doing it well. -+ -+How do you proceed to add a new protocol and what are the requirements? -+ -+## No fixed set of requirements -+ -+This document is an attempt to describe things to consider. There is no -+checklist of the twenty-seven things you need to cross off. We view the entire -+effort as a whole and then judge if it seems to be the right thing - for now. -+The more things that look right, fit our patterns and are done in ways that -+align with our thinking, the better are the chances that we agree that -+supporting this protocol is a grand idea. -+ -+## Mutual benefit is preferred -+ -+curl is not here for your protocol. Your protocol is not here for curl. The -+best cooperation and end result occur when all involved parties mutually see -+and agree that supporting this protocol in curl would be good for everyone. -+Heck, for the world. -+ -+Consider "selling us" the idea that we need an implementation merged in curl, -+to be fairly important. *Why* do we want curl to support this new protocol? -+ -+## Protocol requirements -+ -+### Client-side -+ -+The protocol implementation is for a client's side of a "communication -+session". -+ -+### Transfer oriented -+ -+The protocol itself should be focused on *transfers*. Be it uploads or -+downloads or both. It should at least be possible to view the transfers as -+such, like we can view reading emails over POP3 as a download and sending -+emails over SMTP as an upload. -+ -+If you cannot even shoehorn the protocol into a transfer focused view, then -+you are up for a tough argument. -+ -+### URL -+ -+There should be a documented URL format. If there is an RFC for it there is no -+question about it but the syntax does not have to be a published RFC. It could -+be enough if it is already in use by other implementations. -+ -+If you make up the syntax just in order to be able to propose it to curl, then -+you are in a bad place. URLs are designed and defined for interoperability. -+There should at least be a good chance that other clients and servers can be -+implemented supporting the same URL syntax and work the same or similar way. -+ -+URLs work on registered 'schemes'. There is a register of [all officially -+recognized -+schemes](https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml). If -+your protocol is not in there, is it really a protocol we want? -+ -+### Wide and public use -+ -+The protocol shall already be used or have an expectation of getting used -+widely. Experimental protocols are better off worked on in experiments first, -+to prove themselves before they are adopted by curl. -+ -+## Code -+ -+Of course the code needs to be written, provided, licensed agreeably and it -+should follow our code guidelines and review comments have to be dealt with. -+If the implementation needs third party code, that third party code should not -+have noticeably lesser standards than the curl project itself. -+ -+## Tests -+ -+As much of the protocol implementation as possible needs to be verified by -+curl test cases. We must have the implementation get tested by CI jobs, -+torture tests and more. -+ -+We have experienced many times in the past how new implementations were brought -+to curl and immediately once the code had been merged, the originator vanished -+from the face of the earth. That is fine, but we need to take the necessary -+precautions so when it happens we are still fine. -+ -+Our test infrastructure is powerful enough to test just about every possible -+protocol - but it might require a bit of an effort to make it happen. -+ -+## Documentation -+ -+We cannot assume that users are particularly familiar with details and -+peculiarities of the protocol. It needs documentation. -+ -+Maybe it even needs some internal documentation so that the developers who try -+to debug something five years from now can figure out functionality a little -+easier. -+ -+The protocol specification itself should be freely available without requiring -+a non-disclosure agreement or similar. -+ -+## Do not compare -+ -+We are constantly raising the bar and we are constantly improving the project. -+A lot of things we did in the past would not be acceptable if done today. -+Therefore, you might be tempted to use shortcuts or "hacks" you can spot -+other - existing - protocol implementations have used, but there is nothing to -+gain from that. The bar has been raised. Former "cheats" may not tolerated -+anymore. -diff --git a/docs/internals/README.md b/docs/internals/README.md -new file mode 100644 -index 000000000..289b360ad ---- /dev/null -+++ b/docs/internals/README.md -@@ -0,0 +1,12 @@ -+ -+ -+# Internals -+ -+This directory contains documentation covering libcurl internals; APIs and -+concepts that are useful for contributors and maintainers. -+ -+Public APIs are documented in the public documentation, not here. -diff --git a/docs/internals/SPLAY.md b/docs/internals/SPLAY.md -new file mode 100644 -index 000000000..29cf3858a ---- /dev/null -+++ b/docs/internals/SPLAY.md -@@ -0,0 +1,111 @@ -+ -+ -+# `splay` -+ -+ #include "splay.h" -+ -+This is an internal module for splay tree management. A splay tree is a binary -+search tree with the additional property that recently accessed elements are -+quick to access again. A self-balancing tree. -+ -+Nodes are added to the tree, they are accessed and removed from the tree and -+it automatically rebalances itself in each operation. -+ -+## libcurl use -+ -+libcurl adds fixed timeout expiry timestamps to the splay tree, and is meant -+to scale up to holding a huge amount of pending timeouts with decent -+performance. -+ -+The splay tree is used to: -+ -+1. figure out the next timeout expiry value closest in time -+2. iterate over timeouts that already have expired -+ -+This splay tree rebalances itself based on the time value. -+ -+Each node in the splay tree points to a `struct Curl_easy`. Each `Curl_easy` -+struct is represented only once in the tree. To still allow each easy handle -+to have a large number of timeouts per handle, each handle has a sorted linked -+list of pending timeouts. Only the handle's timeout that is closest to expire -+is the timestamp used for the splay tree node. -+ -+When a specific easy handle's timeout expires, the node gets removed from the -+splay tree and from the handle's linked list of timeouts. The next timeout for -+that handle is then first in line and becomes the new timeout value as the -+node is re-added to the splay. -+ -+## `Curl_splay` -+ -+~~~c -+struct Curl_tree *Curl_splay(struct curltime i, struct Curl_tree *t); -+~~~ -+ -+Rearranges the tree `t` after the provide time `i`. -+ -+## `Curl_splayinsert` -+ -+~~~c -+struct Curl_tree *Curl_splayinsert(struct curltime key, -+ struct Curl_tree *t, -+ struct Curl_tree *node); -+~~~ -+ -+This function inserts a new `node` in the tree, using the given `key` -+timestamp. The `node` struct has a field called `->payload` that can be set to -+point to anything. libcurl sets this to the `struct Curl_easy` handle that is -+associated with the timeout value set in `key`. -+ -+The splay insert function does not allocate any memory, it assumes the caller -+has that arranged. -+ -+It returns a pointer to the new tree root. -+ -+## `Curl_splaygetbest` -+ -+~~~c -+struct Curl_tree *Curl_splaygetbest(struct curltime key, -+ struct Curl_tree *tree, -+ struct Curl_tree **removed); -+~~~ -+ -+If there is a node in the `tree` that has a time value that is less than the -+provided `key`, this function removes that node from the tree and provides it -+in the `*removed` pointer (or NULL if there was no match). -+ -+It returns a pointer to the new tree root. -+ -+## `Curl_splayremove` -+ -+~~~c -+int Curl_splayremove(struct Curl_tree *tree, -+ struct Curl_tree *node, -+ struct Curl_tree **newroot); -+~~~ -+ -+Removes a given `node` from a splay `tree`, and returns the `newroot` -+identifying the new tree root. -+ -+Note that a clean tree without any nodes present implies a NULL pointer. -+ -+## `Curl_splayset` -+ -+~~~c -+void Curl_splayset(struct Curl_tree *node, void *payload); -+~~~ -+ -+Set a custom pointer to be stored in the splay node. This pointer is not used -+by the splay code itself and can be retrieved again with `Curl_splayget`. -+ -+## `Curl_splayget` -+ -+~~~c -+void *Curl_splayget(struct Curl_tree *node); -+~~~ -+ -+Get the custom pointer from the splay node that was previously set with -+`Curl_splayset`. If no pointer was set before, it returns NULL. -diff --git a/docs/internals/WEBSOCKET.md b/docs/internals/WEBSOCKET.md -new file mode 100644 -index 000000000..14caec240 ---- /dev/null -+++ b/docs/internals/WEBSOCKET.md -@@ -0,0 +1,134 @@ -+ -+ -+# WebSocket in curl -+ -+## URL -+ -+WebSocket communication with libcurl is done by setting up a transfer to a URL -+using the `ws://` or `wss://` URL schemes. The latter one being the secure -+version done over HTTPS. -+ -+When using `wss://` to do WebSocket over HTTPS, the standard TLS and HTTPS -+options are acknowledged for the CA, verification of server certificate etc. -+ -+WebSocket communication is done by upgrading a connection from either HTTP or -+HTTPS. When given a WebSocket URL to work with, libcurl considers it a -+transfer failure if the upgrade procedure fails. This means that a plain HTTP -+200 response code is considered an error for this work. -+ -+## API -+ -+The WebSocket API is described in the individual man pages for the new API. -+ -+WebSocket with libcurl can be done two ways. -+ -+1. Get the WebSocket frames from the server sent to the write callback. You -+ can then respond with `curl_ws_send()` from within the callback (or outside -+ of it). -+ -+2. Set `CURLOPT_CONNECT_ONLY` to 2L (new for WebSocket), which makes libcurl -+ do an HTTP GET + `Upgrade:` request plus response in the -+ `curl_easy_perform()` call before it returns and then you can use -+ `curl_ws_recv()` and `curl_ws_send()` to receive and send WebSocket frames -+ from and to the server. -+ -+The new options to `curl_easy_setopt()`: -+ -+ `CURLOPT_WS_OPTIONS` - to control specific behavior. `CURLWS_RAW_MODE` makes -+ libcurl provide all WebSocket traffic raw in the callback. -+ -+The new function calls: -+ -+ `curl_ws_recv()` - receive a WebSocket frame -+ -+ `curl_ws_send()` - send a WebSocket frame -+ -+ `curl_ws_meta()` - return WebSocket metadata within a write callback -+ -+## Max frame size -+ -+The current implementation only supports frame sizes up to a max (64K right -+now). This is because the API delivers full frames and it then cannot manage -+the full 2^63 bytes size. -+ -+If we decide we need to support (much) larger frames than 64K, we need to -+adjust the API accordingly to be able to deliver partial frames in both -+directions. -+ -+## Errors -+ -+If the given WebSocket URL (using `ws://` or `wss://`) fails to get upgraded -+via a 101 response code and instead gets another response code back from the -+HTTP server - the transfer returns `CURLE_HTTP_RETURNED_ERROR` for that -+transfer. Note then that even 2xx response codes are then considered error -+since it failed to provide a WebSocket transfer. -+ -+## Test suite -+ -+I looked for an existing small WebSocket server implementation with maximum -+flexibility to dissect and cram into the test suite but I ended up deciding -+that extending the existing test suite server sws to deal with WebSocket -+might be the better way. -+ -+- This server is already integrated and working in the test suite -+ -+- We want maximum control and ability to generate broken protocol and negative -+ tests as well. A dumber and simpler TCP server could then be easier to -+ massage into this than a "proper" WebSocket server. -+ -+## Command line tool WebSocket -+ -+The plan is to make curl do WebSocket similar to telnet/nc. That part of the -+work has not been started. -+ -+Ideas: -+ -+ - Read stdin and send off as messages. Consider newline as end of fragment. -+ (default to text? offer option to set binary) -+ - Respond to PINGs automatically -+ - Issue PINGs at some default interval (option to switch off/change interval?) -+ - Allow `-d` to specify (initial) data to send (should the format allow for -+ multiple separate frames?) -+ - Exit after N messages received, where N can be zero. -+ -+## Future work -+ -+- Verify the Sec-WebSocket-Accept response. It requires a sha-1 function. -+- Verify Sec-WebSocket-Extensions and Sec-WebSocket-Protocol in the response -+- Make WebSocket work with hyper -+- Consider a `curl_ws_poll()` -+- Make sure WebSocket code paths are fuzzed -+- Add client-side PING interval -+- Provide option to disable PING-PONG automation -+- Support compression (`CURLWS_COMPRESS`) -+ -+## Why not libWebSocket -+ -+libWebSocket is said to be a solid, fast and efficient WebSocket library with -+a vast amount of users. My plan was originally to build upon it to skip having -+to implement the low level parts of WebSocket myself. -+ -+Here are the reasons why I have decided to move forward with WebSocket in -+curl **without using libWebSocket**: -+ -+- doxygen generated docs only makes them hard to navigate. No tutorial, no -+ clearly written explanatory pages for specific functions. -+ -+- seems (too) tightly integrated with a specific TLS library, while we want to -+ support WebSocket with whatever TLS library libcurl was already made to -+ work with. -+ -+- seems (too) tightly integrated with event libraries -+ -+- the references to threads and thread-pools in code and APIs indicate too -+ much logic for our purposes -+ -+- "bloated" - it is a *huge* library that is actually more lines of code than -+ libcurl itself -+ -+- WebSocket is a fairly simple protocol on the network/framing layer so -+ making a homegrown handling of it should be fine -diff --git a/docs/libcurl/CMakeLists.txt b/docs/libcurl/CMakeLists.txt -index 2aa051edd..4af47af34 100644 ---- a/docs/libcurl/CMakeLists.txt -+++ b/docs/libcurl/CMakeLists.txt -@@ -21,33 +21,51 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --# Load man_MANS from shared file -+# Get 'man_MANS' variable - transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - - function(add_manual_pages _listname) -- foreach(_file IN LISTS ${_listname}) -- set(_rofffile "${CMAKE_CURRENT_BINARY_DIR}/${_file}") -+ # Maximum number of files per command to stay within shell/OS limits -+ if(CMAKE_HOST_UNIX) -+ set(_files_per_batch 10000) -+ else() # e.g. Windows with cmd.exe and other obsolete/unidentified shells -+ set(_files_per_batch 200) -+ endif() -+ set(_file_count 0) -+ unset(_rofffiles) -+ unset(_mdfiles) -+ set(_eol "_EOL_") -+ foreach(_file IN LISTS ${_listname} _eol) -+ math(EXPR _file_count "${_file_count} + 1") -+ if(_file_count GREATER_EQUAL _files_per_batch OR _file STREQUAL "_EOL_") -+ add_custom_command(OUTPUT ${_rofffiles} -+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -+ COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/cd2nroff" -k -d "${CMAKE_CURRENT_BINARY_DIR}" ${_mdfiles} -+ DEPENDS ${_mdfiles} -+ VERBATIM -+ ) -+ set(_file_count 0) -+ unset(_rofffiles) -+ unset(_mdfiles) -+ endif() -+ -+ list(APPEND _rofffiles "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - if(_file STREQUAL "libcurl-symbols.3") - # Special case, an auto-generated file. - string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_BINARY_DIR}/${_file}") - else() -- string(REPLACE ".3" ".md" _mdfile "${CMAKE_CURRENT_SOURCE_DIR}/${_file}") -+ string(REPLACE ".3" ".md" _mdfile "${_file}") - endif() -- add_custom_command(OUTPUT "${_rofffile}" -- COMMAND "${PERL_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/scripts/cd2nroff ${_mdfile} > ${_rofffile} -- DEPENDS "${_mdfile}" -- VERBATIM -- ) -+ list(APPEND _mdfiles "${_mdfile}") - endforeach() -- - endfunction() - --add_custom_command(OUTPUT libcurl-symbols.md -+add_custom_command(OUTPUT "libcurl-symbols.md" - COMMAND - "${PERL_EXECUTABLE}" - "${CMAKE_CURRENT_SOURCE_DIR}/mksymbolsmanpage.pl" < -- "${CMAKE_CURRENT_SOURCE_DIR}/symbols-in-versions" > libcurl-symbols.md -+ "${CMAKE_CURRENT_SOURCE_DIR}/symbols-in-versions" > "libcurl-symbols.md" - DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/symbols-in-versions" - "${CMAKE_CURRENT_SOURCE_DIR}/mksymbolsmanpage.pl" -@@ -55,13 +73,13 @@ add_custom_command(OUTPUT libcurl-symbols.md - ) - - add_manual_pages(man_MANS) --add_custom_target(man ALL DEPENDS ${man_MANS}) -+add_custom_target(curl-man ALL DEPENDS ${man_MANS}) - if(NOT CURL_DISABLE_INSTALL) - unset(_src) -- foreach(_f ${man_MANS}) -+ foreach(_f IN LISTS man_MANS) - list(APPEND _src "${CMAKE_CURRENT_BINARY_DIR}/${_f}") - endforeach() -- install(FILES ${_src} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) -+ install(FILES ${_src} DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") - endif() - - add_subdirectory(opts) -diff --git a/docs/libcurl/Makefile.inc b/docs/libcurl/Makefile.inc -index 336b4192e..fe990cc1e 100644 ---- a/docs/libcurl/Makefile.inc -+++ b/docs/libcurl/Makefile.inc -@@ -87,6 +87,7 @@ man_MANS = \ - curl_multi_timeout.3 \ - curl_multi_wakeup.3 \ - curl_multi_wait.3 \ -+ curl_multi_waitfds.3 \ - curl_pushheader_bynum.3 \ - curl_pushheader_byname.3 \ - curl_share_cleanup.3 \ -diff --git a/docs/libcurl/curl_easy_cleanup.md b/docs/libcurl/curl_easy_cleanup.md -index e939dddc7..fc653e3a5 100644 ---- a/docs/libcurl/curl_easy_cleanup.md -+++ b/docs/libcurl/curl_easy_cleanup.md -@@ -12,11 +12,12 @@ See-also: - - curl_multi_remove_handle (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_easy_cleanup - End a libcurl easy handle -+curl_easy_cleanup - free an easy handle - - # SYNOPSIS - -@@ -52,6 +53,8 @@ before it is closed. - Passing in a NULL pointer in *handle* makes this function return immediately - with no action. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_duphandle.md b/docs/libcurl/curl_easy_duphandle.md -index 49d95ad98..45e738f30 100644 ---- a/docs/libcurl/curl_easy_duphandle.md -+++ b/docs/libcurl/curl_easy_duphandle.md -@@ -11,11 +11,12 @@ See-also: - - curl_global_init (3) - Protocol: - - All -+Added-in: 7.9 - --- - - # NAME - --curl_easy_duphandle - Clone a libcurl session handle -+curl_easy_duphandle - clone an easy handle - - # SYNOPSIS - -@@ -46,6 +47,8 @@ data from the main filename to populate the cache. - In multi-threaded programs, this function must be called in a synchronous way, - the input handle may not be in use when cloned. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_escape.md b/docs/libcurl/curl_easy_escape.md -index dfe4bf5f3..b10500ac2 100644 ---- a/docs/libcurl/curl_easy_escape.md -+++ b/docs/libcurl/curl_easy_escape.md -@@ -6,14 +6,16 @@ Section: 3 - Source: libcurl - See-also: - - curl_easy_unescape (3) -- - curl_free (3) -+ - curl_url_set (3) -+ - curl_url_get (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME - --curl_easy_escape - URL encodes the given string -+curl_easy_escape - URL encode a string - - # SYNOPSIS - -@@ -25,18 +27,14 @@ char *curl_easy_escape(CURL *curl, const char *string, int length); - - # DESCRIPTION - --This function converts the given input *string* to a URL encoded string --and returns that as a new allocated string. All input characters that are not --a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" --version (**%NN** where **NN** is a two-digit hexadecimal number). -+This function converts the given input *string* to a URL encoded string and -+returns that as a new allocated string. All input characters that are not a-z, -+A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" version -+(**%NN** where **NN** is a two-digit hexadecimal number). - --If *length* is set to 0 (zero), curl_easy_escape(3) uses strlen() on --the input *string* to find out the size. This function does not accept --input strings longer than **CURL_MAX_INPUT_LENGTH** (8 MB). -- --Since 7.82.0, the **curl** parameter is ignored. Prior to that there was --per-handle character conversion support for some old operating systems such as --TPF, but it was otherwise ignored. -+If *length* is set to 0 (zero), curl_easy_escape(3) uses strlen() on the input -+*string* to find out the size. This function does not accept input strings -+longer than **CURL_MAX_INPUT_LENGTH** (8 MB). - - You must curl_free(3) the returned string when you are done with it. - -@@ -51,6 +49,19 @@ uses. - The caller of curl_easy_escape(3) must make sure that the data passed in - to the function is encoded correctly. - -+# URLs -+ -+URLs are by definition *URL encoded*. To create a proper URL from a set of -+components that may not be URL encoded already, you cannot just URL encode the -+entire URL string with curl_easy_escape(3), because it then also converts -+colons, slashes and other symbols that you probably want untouched. -+ -+To create a proper URL from strings that are not already URL encoded, we -+recommend using libcurl's URL API: set the pieces with curl_url_set(3) and get -+the final correct URL with curl_url_get(3). -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,9 +79,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Since 7.82.0, the **curl** parameter is ignored. Prior to that there was -+per-handle character conversion support for some old operating systems such as -+TPF, but it was otherwise ignored. - --Added in 7.15.4 and replaces the old curl_escape(3) function. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_getinfo.md b/docs/libcurl/curl_easy_getinfo.md -index a4e4e4715..31efc3165 100644 ---- a/docs/libcurl/curl_easy_getinfo.md -+++ b/docs/libcurl/curl_easy_getinfo.md -@@ -8,6 +8,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -33,362 +34,345 @@ performed transfer if you want to get transfer related data. - You should not free the memory returned by this function unless it is - explicitly mentioned below. - --# AVAILABLE INFORMATION -+# OPTIONS - - The following information can be extracted: - --## CURLINFO_EFFECTIVE_METHOD -+## CURLINFO_ACTIVESOCKET - --Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3) -+The session's active socket. See CURLINFO_ACTIVESOCKET(3) - --## CURLINFO_EFFECTIVE_URL -+## CURLINFO_APPCONNECT_TIME - --Last used URL. See CURLINFO_EFFECTIVE_URL(3) -+The time it took from the start until the SSL connect/handshake with the -+remote host was completed as a double in number of seconds. (Added in 7.19.0) - --## CURLINFO_RESPONSE_CODE -+## CURLINFO_APPCONNECT_TIME_T - --Last received response code. See CURLINFO_RESPONSE_CODE(3) -+The time it took from the start until the SSL connect/handshake with the -+remote host was completed in number of microseconds. (Added in 7.60.0) See -+CURLINFO_APPCONNECT_TIME_T(3) - --## CURLINFO_REFERER -+## CURLINFO_CAINFO - --Referrer header. See CURLINFO_REFERER(3) -+Get the default value for CURLOPT_CAINFO(3). See CURLINFO_CAINFO(3) - --## CURLINFO_HTTP_CONNECTCODE -+## CURLINFO_CAPATH - --Last proxy CONNECT response code. See CURLINFO_HTTP_CONNECTCODE(3) -+Get the default value for CURLOPT_CAPATH(3). See CURLINFO_CAPATH(3) - --## CURLINFO_HTTP_VERSION -+## CURLINFO_CERTINFO - --The http version used in the connection. See CURLINFO_HTTP_VERSION(3) -+Certificate chain. See CURLINFO_CERTINFO(3) - --## CURLINFO_FILETIME -+## CURLINFO_CONDITION_UNMET - --Remote time of the retrieved document. See CURLINFO_FILETIME(3) -+Whether or not a time conditional was met or 304 HTTP response. -+See CURLINFO_CONDITION_UNMET(3) - --## CURLINFO_FILETIME_T -+## CURLINFO_CONNECT_TIME - --Remote time of the retrieved document. See CURLINFO_FILETIME_T(3) -+The time it took from the start until the connect to the remote host (or -+proxy) was completed. As a double. See CURLINFO_CONNECT_TIME(3) - --## CURLINFO_TOTAL_TIME -+## CURLINFO_CONNECT_TIME_T - --Total time of previous transfer. See CURLINFO_TOTAL_TIME(3) -+The time it took from the start until the connect to the remote host (or -+proxy) was completed. In microseconds. See CURLINFO_CONNECT_TIME_T(3). - --## CURLINFO_TOTAL_TIME_T -+## CURLINFO_CONN_ID - --Total time of previous transfer. See CURLINFO_TOTAL_TIME_T(3) -+The ID of the last connection used by the transfer. (Added in 8.2.0) -+See CURLINFO_CONN_ID(3) - --## CURLINFO_NAMELOOKUP_TIME -+## CURLINFO_CONTENT_LENGTH_DOWNLOAD - --Time from start until name resolving completed. See --CURLINFO_NAMELOOKUP_TIME(3) -+(**Deprecated**) Content length from the Content-Length header. -+See CURLINFO_CONTENT_LENGTH_DOWNLOAD(3) - --## CURLINFO_NAMELOOKUP_TIME_T -+## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T - --Time from start until name resolving completed. See --CURLINFO_NAMELOOKUP_TIME_T(3) -+Content length from the Content-Length header. -+See CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) - --## CURLINFO_CONNECT_TIME -+## CURLINFO_CONTENT_LENGTH_UPLOAD - --Time from start until remote host or proxy completed. --See CURLINFO_CONNECT_TIME(3) -+(**Deprecated**) Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD(3) - --## CURLINFO_CONNECT_TIME_T -+## CURLINFO_CONTENT_LENGTH_UPLOAD_T - --Time from start until remote host or proxy completed. --See CURLINFO_CONNECT_TIME_T(3) -+Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) - --## CURLINFO_APPCONNECT_TIME -+## CURLINFO_CONTENT_TYPE - --Time from start until SSL/SSH handshake completed. --See CURLINFO_APPCONNECT_TIME(3) -+Content type from the `Content-Type:` header. We recommend using -+curl_easy_header(3) instead. See CURLINFO_CONTENT_TYPE(3) - --## CURLINFO_APPCONNECT_TIME_T -+## CURLINFO_COOKIELIST - --Time from start until SSL/SSH handshake completed. --See CURLINFO_APPCONNECT_TIME_T(3) -+List of all known cookies. See CURLINFO_COOKIELIST(3) - --## CURLINFO_PRETRANSFER_TIME -+## CURLINFO_EARLYDATA_SENT_T - --Time from start until just before the transfer begins. --See CURLINFO_PRETRANSFER_TIME(3) -+Amount of TLS early data sent (in number of bytes) when -+CURLSSLOPT_EARLYDATA is enabled. - --## CURLINFO_PRETRANSFER_TIME_T -+## CURLINFO_EFFECTIVE_METHOD - --Time from start until just before the transfer begins. --See CURLINFO_PRETRANSFER_TIME_T(3) -+Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3) - --## CURLINFO_QUEUE_TIME_T -+## CURLINFO_EFFECTIVE_URL - --Time during which this transfer was held in a waiting queue. --See CURLINFO_QUEUE_TIME_T(3) -+Last used URL. See CURLINFO_EFFECTIVE_URL(3) - --## CURLINFO_USED_PROXY -+## CURLINFO_FILETIME - --Whether the proxy was used (Added in 8.7.0). See CURLINFO_USED_PROXY(3) -+Remote time of the retrieved document. See CURLINFO_FILETIME(3) - --## CURLINFO_STARTTRANSFER_TIME -+## CURLINFO_FILETIME_T - --Time from start until just when the first byte is received. --See CURLINFO_STARTTRANSFER_TIME(3) -+Remote time of the retrieved document. See CURLINFO_FILETIME_T(3) - --## CURLINFO_STARTTRANSFER_TIME_T -+## CURLINFO_FTP_ENTRY_PATH - --Time from start until just when the first byte is received. --See CURLINFO_STARTTRANSFER_TIME_T(3) -+The entry path after logging in to an FTP server. See -+CURLINFO_FTP_ENTRY_PATH(3) - --## CURLINFO_REDIRECT_TIME -+## CURLINFO_HEADER_SIZE - --Time taken for all redirect steps before the final transfer. --See CURLINFO_REDIRECT_TIME(3) -+Number of bytes of all headers received. See CURLINFO_HEADER_SIZE(3) - --## CURLINFO_REDIRECT_TIME_T -+## CURLINFO_HTTPAUTH_AVAIL - --Time taken for all redirect steps before the final transfer. --See CURLINFO_REDIRECT_TIME_T(3) -+Available HTTP authentication methods. See CURLINFO_HTTPAUTH_AVAIL(3) - --## CURLINFO_REDIRECT_COUNT -+## CURLINFO_HTTP_CONNECTCODE - --Total number of redirects that were followed. --See CURLINFO_REDIRECT_COUNT(3) -+Last proxy CONNECT response code. See CURLINFO_HTTP_CONNECTCODE(3) - --## CURLINFO_REDIRECT_URL -+## CURLINFO_HTTP_VERSION - --URL a redirect would take you to, had you enabled redirects. --See CURLINFO_REDIRECT_URL(3) -+The http version used in the connection. See CURLINFO_HTTP_VERSION(3) - --## CURLINFO_SIZE_UPLOAD -+## CURLINFO_LASTSOCKET - --(Deprecated) Number of bytes uploaded. --See CURLINFO_SIZE_UPLOAD(3) -+(**Deprecated**) Last socket used. See CURLINFO_LASTSOCKET(3) - --## CURLINFO_SIZE_UPLOAD_T -+## CURLINFO_LOCAL_IP - --Number of bytes uploaded. --See CURLINFO_SIZE_UPLOAD_T(3) -+Source IP address of the last connection. See CURLINFO_LOCAL_IP(3) - --## CURLINFO_SIZE_DOWNLOAD -+## CURLINFO_LOCAL_PORT - --(Deprecated) Number of bytes downloaded. --See CURLINFO_SIZE_DOWNLOAD(3) -+Source port number of the last connection. See CURLINFO_LOCAL_PORT(3) - --## CURLINFO_SIZE_DOWNLOAD_T -+## CURLINFO_NAMELOOKUP_TIME - --Number of bytes downloaded. --See CURLINFO_SIZE_DOWNLOAD_T(3) -+Time from start until name resolving completed as a double. See -+CURLINFO_NAMELOOKUP_TIME(3) - --## CURLINFO_SPEED_DOWNLOAD -+## CURLINFO_NAMELOOKUP_TIME_T - --(Deprecated) Average download speed. --See CURLINFO_SPEED_DOWNLOAD(3) -+Time from start until name resolving completed in number of microseconds. See -+CURLINFO_NAMELOOKUP_TIME_T(3) - --## CURLINFO_SPEED_DOWNLOAD_T -+## CURLINFO_NUM_CONNECTS - --Average download speed. --See CURLINFO_SPEED_DOWNLOAD_T(3) -+Number of new successful connections used for previous transfer. -+See CURLINFO_NUM_CONNECTS(3) - --## CURLINFO_SPEED_UPLOAD -+## CURLINFO_OS_ERRNO - --(Deprecated) Average upload speed. --See CURLINFO_SPEED_UPLOAD(3) -+The errno from the last failure to connect. See CURLINFO_OS_ERRNO(3) - --## CURLINFO_SPEED_UPLOAD_T -+## CURLINFO_POSTTRANSFER_TIME_T - --Average upload speed. --See CURLINFO_SPEED_UPLOAD_T(3) -+The time it took from the start until the last byte is sent by libcurl. -+In microseconds. (Added in 8.10.0) See CURLINFO_POSTTRANSFER_TIME_T(3) - --## CURLINFO_HEADER_SIZE -+## CURLINFO_PRETRANSFER_TIME - --Number of bytes of all headers received. --See CURLINFO_HEADER_SIZE(3) -+The time it took from the start until the file transfer is just about to -+begin. This includes all pre-transfer commands and negotiations that are -+specific to the particular protocol(s) involved. See -+CURLINFO_PRETRANSFER_TIME(3) - --## CURLINFO_REQUEST_SIZE -+## CURLINFO_PRETRANSFER_TIME_T - --Number of bytes sent in the issued HTTP requests. --See CURLINFO_REQUEST_SIZE(3) -+The time it took from the start until the file transfer is just about to -+begin. This includes all pre-transfer commands and negotiations that are -+specific to the particular protocol(s) involved. In microseconds. See -+CURLINFO_PRETRANSFER_TIME_T(3) - --## CURLINFO_SSL_VERIFYRESULT -+## CURLINFO_PRIMARY_IP - --Certificate verification result. --See CURLINFO_SSL_VERIFYRESULT(3) -+Destination IP address of the last connection. See CURLINFO_PRIMARY_IP(3) - --## CURLINFO_PROXY_ERROR -+## CURLINFO_PRIMARY_PORT - --Detailed proxy error. --See CURLINFO_PROXY_ERROR(3) -+Destination port of the last connection. See CURLINFO_PRIMARY_PORT(3) - --## CURLINFO_PROXY_SSL_VERIFYRESULT -+## CURLINFO_PRIVATE - --Proxy certificate verification result. --See CURLINFO_PROXY_SSL_VERIFYRESULT(3) -+User's private data pointer. See CURLINFO_PRIVATE(3) - --## CURLINFO_SSL_ENGINES -+## CURLINFO_PROTOCOL - --A list of OpenSSL crypto engines. --See CURLINFO_SSL_ENGINES(3) -+(**Deprecated**) The protocol used for the connection. (Added in 7.52.0) See -+CURLINFO_PROTOCOL(3) - --## CURLINFO_CONTENT_LENGTH_DOWNLOAD -+## CURLINFO_PROXYAUTH_AVAIL - --(Deprecated) Content length from the Content-Length header. --See CURLINFO_CONTENT_LENGTH_DOWNLOAD(3) -+Available HTTP proxy authentication methods. See CURLINFO_PROXYAUTH_AVAIL(3) - --## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T -+## CURLINFO_PROXY_ERROR - --Content length from the Content-Length header. --See CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) -+Detailed proxy error. See CURLINFO_PROXY_ERROR(3) - --## CURLINFO_CONTENT_LENGTH_UPLOAD -+## CURLINFO_PROXY_SSL_VERIFYRESULT - --(Deprecated) Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD(3) -+Proxy certificate verification result. See CURLINFO_PROXY_SSL_VERIFYRESULT(3) - --## CURLINFO_CONTENT_LENGTH_UPLOAD_T -+## CURLINFO_QUEUE_TIME_T - --Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) -+The time during which the transfer was held in a waiting queue before it could -+start for real in number of microseconds. (Added in 8.6.0) See -+CURLINFO_QUEUE_TIME_T(3) - --## CURLINFO_CONTENT_TYPE -+## CURLINFO_REDIRECT_COUNT - --Content type from the Content-Type header. --See CURLINFO_CONTENT_TYPE(3) -+Total number of redirects that were followed. See CURLINFO_REDIRECT_COUNT(3) - --## CURLINFO_RETRY_AFTER -+## CURLINFO_REDIRECT_TIME - --The value from the Retry-After header. --See CURLINFO_RETRY_AFTER(3) -+The time it took for all redirection steps include name lookup, connect, -+pretransfer and transfer before final transaction was started. So, this is -+zero if no redirection took place. As a double. See CURLINFO_REDIRECT_TIME(3) - --## CURLINFO_PRIVATE -+## CURLINFO_REDIRECT_TIME_T - --User's private data pointer. --See CURLINFO_PRIVATE(3) -+The time it took for all redirection steps include name lookup, connect, -+pretransfer and transfer before final transaction was started. So, this is -+zero if no redirection took place. In number of microseconds. See -+CURLINFO_REDIRECT_TIME_T(3) - --## CURLINFO_HTTPAUTH_AVAIL -+## CURLINFO_REDIRECT_URL - --Available HTTP authentication methods. --See CURLINFO_HTTPAUTH_AVAIL(3) -+URL a redirect would take you to, had you enabled redirects. See -+CURLINFO_REDIRECT_URL(3) - --## CURLINFO_PROXYAUTH_AVAIL -+## CURLINFO_REFERER - --Available HTTP proxy authentication methods. --See CURLINFO_PROXYAUTH_AVAIL(3) -+Referrer header. See CURLINFO_REFERER(3) - --## CURLINFO_OS_ERRNO -+## CURLINFO_REQUEST_SIZE - --The errno from the last failure to connect. --See CURLINFO_OS_ERRNO(3) -+Number of bytes sent in the issued HTTP requests. See CURLINFO_REQUEST_SIZE(3) - --## CURLINFO_NUM_CONNECTS -+## CURLINFO_RESPONSE_CODE - --Number of new successful connections used for previous transfer. --See CURLINFO_NUM_CONNECTS(3) -+Last received response code. See CURLINFO_RESPONSE_CODE(3) - --## CURLINFO_PRIMARY_IP -+## CURLINFO_RETRY_AFTER - --Destination IP address of the last connection. --See CURLINFO_PRIMARY_IP(3) -+The value from the Retry-After header. See CURLINFO_RETRY_AFTER(3) - --## CURLINFO_PRIMARY_PORT -+## CURLINFO_RTSP_CLIENT_CSEQ - --Destination port of the last connection. --See CURLINFO_PRIMARY_PORT(3) -+The RTSP client CSeq that is expected next. See CURLINFO_RTSP_CLIENT_CSEQ(3) - --## CURLINFO_LOCAL_IP -+## CURLINFO_RTSP_CSEQ_RECV - --Source IP address of the last connection. --See CURLINFO_LOCAL_IP(3) -+RTSP CSeq last received. See CURLINFO_RTSP_CSEQ_RECV(3) - --## CURLINFO_LOCAL_PORT -+## CURLINFO_RTSP_SERVER_CSEQ - --Source port number of the last connection. --See CURLINFO_LOCAL_PORT(3) -+The RTSP server CSeq that is expected next. See CURLINFO_RTSP_SERVER_CSEQ(3) - --## CURLINFO_COOKIELIST -+## CURLINFO_RTSP_SESSION_ID - --List of all known cookies. --See CURLINFO_COOKIELIST(3) -+RTSP session ID. See CURLINFO_RTSP_SESSION_ID(3) - --## CURLINFO_LASTSOCKET -+## CURLINFO_SCHEME - --(Deprecated) Last socket used. --See CURLINFO_LASTSOCKET(3) -+The scheme used for the connection. (Added in 7.52.0) See CURLINFO_SCHEME(3) - --## CURLINFO_ACTIVESOCKET -+## CURLINFO_SIZE_DOWNLOAD - --The session's active socket. --See CURLINFO_ACTIVESOCKET(3) -+(**Deprecated**) Number of bytes downloaded. See CURLINFO_SIZE_DOWNLOAD(3) - --## CURLINFO_FTP_ENTRY_PATH -+## CURLINFO_SIZE_DOWNLOAD_T - --The entry path after logging in to an FTP server. --See CURLINFO_FTP_ENTRY_PATH(3) -+Number of bytes downloaded. See CURLINFO_SIZE_DOWNLOAD_T(3) - --## CURLINFO_CAPATH -+## CURLINFO_SIZE_UPLOAD - --Get the default value for CURLOPT_CAPATH(3). --See CURLINFO_CAPATH(3) -+(**Deprecated**) Number of bytes uploaded. See CURLINFO_SIZE_UPLOAD(3) - --## CURLINFO_CAINFO -+## CURLINFO_SIZE_UPLOAD_T - --Get the default value for CURLOPT_CAINFO(3). --See CURLINFO_CAINFO(3) -+Number of bytes uploaded. See CURLINFO_SIZE_UPLOAD_T(3) - --## CURLINFO_CERTINFO -+## CURLINFO_SPEED_DOWNLOAD - --Certificate chain. --See CURLINFO_CERTINFO(3) -+(**Deprecated**) Average download speed. See CURLINFO_SPEED_DOWNLOAD(3) - --## CURLINFO_TLS_SSL_PTR -+## CURLINFO_SPEED_DOWNLOAD_T - --TLS session info that can be used for further processing. --See CURLINFO_TLS_SSL_PTR(3) -+Average download speed. See CURLINFO_SPEED_DOWNLOAD_T(3) - --## CURLINFO_TLS_SESSION -+## CURLINFO_SPEED_UPLOAD - --TLS session info that can be used for further processing. See --CURLINFO_TLS_SESSION(3). Deprecated option, use --CURLINFO_TLS_SSL_PTR(3) instead! -+(**Deprecated**) Average upload speed. See CURLINFO_SPEED_UPLOAD(3) - --## CURLINFO_CONDITION_UNMET -+## CURLINFO_SPEED_UPLOAD_T - --Whether or not a time conditional was met or 304 HTTP response. --See CURLINFO_CONDITION_UNMET(3) -+Average upload speed in number of bytes per second. See -+CURLINFO_SPEED_UPLOAD_T(3) - --## CURLINFO_RTSP_SESSION_ID -+## CURLINFO_SSL_ENGINES - --RTSP session ID. --See CURLINFO_RTSP_SESSION_ID(3) -+A list of OpenSSL crypto engines. See CURLINFO_SSL_ENGINES(3) - --## CURLINFO_RTSP_CLIENT_CSEQ -+## CURLINFO_SSL_VERIFYRESULT - --The RTSP client CSeq that is expected next. --See CURLINFO_RTSP_CLIENT_CSEQ(3) -+Certificate verification result. See CURLINFO_SSL_VERIFYRESULT(3) - --## CURLINFO_RTSP_SERVER_CSEQ -+## CURLINFO_STARTTRANSFER_TIME - --The RTSP server CSeq that is expected next. --See CURLINFO_RTSP_SERVER_CSEQ(3) -+The time it took from the start until the first byte is received by libcurl. -+As a double. See CURLINFO_STARTTRANSFER_TIME(3) - --## CURLINFO_RTSP_CSEQ_RECV -+## CURLINFO_STARTTRANSFER_TIME_T - --RTSP CSeq last received. --See CURLINFO_RTSP_CSEQ_RECV(3) -+The time it took from the start until the first byte is received by libcurl. -+In microseconds. See CURLINFO_STARTTRANSFER_TIME_T(3) - --## CURLINFO_PROTOCOL -+## CURLINFO_TLS_SESSION - --(Deprecated) The protocol used for the connection. (Added in 7.52.0) --See CURLINFO_PROTOCOL(3) -+(**Deprecated**) TLS session info that can be used for further processing. See -+CURLINFO_TLS_SESSION(3). Use CURLINFO_TLS_SSL_PTR(3) instead. - --## CURLINFO_SCHEME -+## CURLINFO_TLS_SSL_PTR - --The scheme used for the connection. (Added in 7.52.0) --See CURLINFO_SCHEME(3) -+TLS session info that can be used for further processing. See -+CURLINFO_TLS_SSL_PTR(3) - --## CURLINFO_CONN_ID -+## CURLINFO_TOTAL_TIME - --The ID of the last connection used by the transfer. (Added in 8.2.0) --See CURLINFO_CONN_ID(3) -+Total time of previous transfer. See CURLINFO_TOTAL_TIME(3) -+ -+## CURLINFO_TOTAL_TIME_T -+ -+Total time of previous transfer. See CURLINFO_TOTAL_TIME_T(3) -+ -+## CURLINFO_USED_PROXY -+ -+Whether the proxy was used (Added in 8.7.0). See CURLINFO_USED_PROXY(3) - - ## CURLINFO_XFER_ID - --The ID of the transfer. (Added in 8.2.0) --See CURLINFO_XFER_ID(3) -+The ID of the transfer. (Added in 8.2.0) See CURLINFO_XFER_ID(3) - - # TIMES - -@@ -401,55 +385,19 @@ An overview of the time values available from curl_easy_getinfo(3) - |--|--|--CONNECT - |--|--|--|--APPCONNECT - |--|--|--|--|--PRETRANSFER -- |--|--|--|--|--|--STARTTRANSFER -- |--|--|--|--|--|--|--TOTAL -- |--|--|--|--|--|--|--REDIRECT -- --## CURLINFO_QUEUE_TIME -+ |--|--|--|--|--|--POSTTRANSFER -+ |--|--|--|--|--|--|--STARTTRANSFER -+ |--|--|--|--|--|--|--|--TOTAL -+ |--|--|--|--|--|--|--|--REDIRECT - --CURLINFO_QUEUE_TIME_T(3). The time during which the transfer was held in a --waiting queue before it could start for real. (Added in 8.6.0) - --## CURLINFO_NAMELOOKUP_TIME -- --CURLINFO_NAMELOOKUP_TIME(3) and CURLINFO_NAMELOOKUP_TIME_T(3). The time it --took from the start until the name resolving was completed. -- --## CURLINFO_CONNECT_TIME -- --CURLINFO_CONNECT_TIME(3) and CURLINFO_CONNECT_TIME_T(3). The time it took from --the start until the connect to the remote host (or proxy) was completed. -- --## CURLINFO_APPCONNECT_TIME -+ CURLINFO_QUEUE_TIME_T(3), CURLINFO_NAMELOOKUP_TIME_T(3), -+ CURLINFO_CONNECT_TIME_T(3), CURLINFO_APPCONNECT_TIME_T(3), -+ CURLINFO_PRETRANSFER_TIME_T(3), CURLINFO_POSTTRANSFER_TIME_T(3), -+ CURLINFO_STARTTRANSFER_TIME_T(3), CURLINFO_TOTAL_TIME_T(3), -+ CURLINFO_REDIRECT_TIME_T(3) - --CURLINFO_APPCONNECT_TIME(3) and CURLINFO_APPCONNECT_TIME_T(3). The time it --took from the start until the SSL connect/handshake with the remote host was --completed. (Added in 7.19.0) The latter is the integer version (measuring --microseconds). (Added in 7.60.0) -- --## CURLINFO_PRETRANSFER_TIME -- --CURLINFO_PRETRANSFER_TIME(3) and CURLINFO_PRETRANSFER_TIME_T(3). The time it --took from the start until the file transfer is just about to begin. This --includes all pre-transfer commands and negotiations that are specific to the --particular protocol(s) involved. -- --## CURLINFO_STARTTRANSFER_TIME -- --CURLINFO_STARTTRANSFER_TIME(3) and CURLINFO_STARTTRANSFER_TIME_T(3). The time --it took from the start until the first byte is received by libcurl. -- --## CURLINFO_TOTAL_TIME -- --CURLINFO_TOTAL_TIME(3) and CURLINFO_TOTAL_TIME_T(3). Total time --of the previous request. -- --## CURLINFO_REDIRECT_TIME -- --CURLINFO_REDIRECT_TIME(3) and CURLINFO_REDIRECT_TIME_T(3). The time it took --for all redirection steps include name lookup, connect, pretransfer and --transfer before final transaction was started. So, this is zero if no --redirection took place. -+# %PROTOCOLS% - - # EXAMPLE - -@@ -477,9 +425,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_header.md b/docs/libcurl/curl_easy_header.md -index 6bc743436..0c7125066 100644 ---- a/docs/libcurl/curl_easy_header.md -+++ b/docs/libcurl/curl_easy_header.md -@@ -12,6 +12,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - HTTP -+Added-in: 7.83.0 - --- - - # NAME -@@ -64,7 +65,7 @@ does not have to bother about multiple headers used wrongly. - - The memory for the returned struct is associated with the easy handle and - subsequent calls to curl_easy_header(3) clobber the struct used in the --previous calls for the same easy handle. Applications need to copy the data if -+previous calls for the same easy handle. The application needs to copy the data if - it wants to keep it around. The memory used for the struct gets freed with - calling curl_easy_cleanup(3) of the easy handle. - -@@ -136,6 +137,8 @@ response that might happen before the "real" response. - - The header is an HTTP/2 or HTTP/3 pseudo header - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -153,9 +156,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.83.0. Officially supported since 7.84.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_init.md b/docs/libcurl/curl_easy_init.md -index 9d282bdf3..3a5d2be41 100644 ---- a/docs/libcurl/curl_easy_init.md -+++ b/docs/libcurl/curl_easy_init.md -@@ -13,11 +13,12 @@ See-also: - - curl_multi_init (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_easy_init - Start a libcurl easy session -+curl_easy_init - create an easy handle - - # SYNOPSIS - -@@ -42,14 +43,16 @@ all the options that were set in the source handle set in the new copy as - well. - - If you did not already call curl_global_init(3) before calling this function, --curl_easy_init(3) does it automatically. This may be lethal in multi-threaded --cases, if curl_global_init(3) is not thread-safe in your system, and it may -+curl_easy_init(3) does it automatically. This can be lethal in multi-threaded -+cases for platforms where curl_global_init(3) is not thread-safe, and it may - then result in resource problems because there is no corresponding cleanup. - - You are strongly advised to not allow this automatic behavior, by calling - curl_global_init(3) yourself properly. See the description in libcurl(3) of - global environment requirements for details of how to use this function. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_nextheader.md b/docs/libcurl/curl_easy_nextheader.md -index 683a9d9d1..2dbdf61cc 100644 ---- a/docs/libcurl/curl_easy_nextheader.md -+++ b/docs/libcurl/curl_easy_nextheader.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_perform (3) - Protocol: - - HTTP -+Added-in: 7.83.0 - --- - - # NAME -@@ -60,6 +61,8 @@ The memory for the struct this points to, is owned and managed by libcurl and - is associated with the easy handle. Applications must copy the data if they - want it to survive subsequent API calls or the life-time of the easy handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -89,9 +92,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.83.0. Officially supported since 7.84.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_option_by_id.md b/docs/libcurl/curl_easy_option_by_id.md -index 697fc7e53..87cdeeb21 100644 ---- a/docs/libcurl/curl_easy_option_by_id.md -+++ b/docs/libcurl/curl_easy_option_by_id.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.73.0 - --- - - # NAME -@@ -35,6 +36,8 @@ well. - - If libcurl has no option with the given id, this function returns NULL. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -47,9 +50,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.73.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_option_by_name.md b/docs/libcurl/curl_easy_option_by_name.md -index d03ff8b43..d237bd354 100644 ---- a/docs/libcurl/curl_easy_option_by_name.md -+++ b/docs/libcurl/curl_easy_option_by_name.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.73.0 - --- - - # NAME -@@ -34,6 +35,8 @@ insensitive. - - If libcurl has no option with the given name, this function returns NULL. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -46,9 +49,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.73.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_option_next.md b/docs/libcurl/curl_easy_option_next.md -index 42f4409b6..836dee2d7 100644 ---- a/docs/libcurl/curl_easy_option_next.md -+++ b/docs/libcurl/curl_easy_option_next.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.73.0 - --- - - # NAME -@@ -66,6 +67,8 @@ struct curl_easyoption { - }; - ~~~ - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -81,9 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.73.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_pause.md b/docs/libcurl/curl_easy_pause.md -index a185acd79..fa8159acd 100644 ---- a/docs/libcurl/curl_easy_pause.md -+++ b/docs/libcurl/curl_easy_pause.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_reset (3) - Protocol: - - All -+Added-in: 7.18.0 - --- - - # NAME -@@ -97,6 +98,8 @@ buffering 32 megabyte of data for a paused stream. - When such a paused stream is unpaused again, any buffered data is delivered - first. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -105,7 +108,7 @@ int main(void) - CURL *curl = curl_easy_init(); - if(curl) { - /* pause a transfer in both directions */ -- curl_easy_pause(curl, CURL_READFUNC_PAUSE | CURL_WRITEFUNC_PAUSE); -+ curl_easy_pause(curl, CURLPAUSE_RECV | CURLPAUSE_SEND); - - } - } -@@ -131,9 +134,7 @@ size worth of data that curl cannot stop but instead needs to cache while the - transfer is paused. This means that if a window size of 64 MB is used, libcurl - might end up having to cache 64 MB of data. - --# AVAILABILITY -- --Added in 7.18.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_perform.md b/docs/libcurl/curl_easy_perform.md -index b24ae50db..4c4c5668e 100644 ---- a/docs/libcurl/curl_easy_perform.md -+++ b/docs/libcurl/curl_easy_perform.md -@@ -12,11 +12,12 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_easy_perform - perform a blocking file transfer -+curl_easy_perform - perform a blocking network transfer - - # SYNOPSIS - -@@ -58,6 +59,8 @@ CURLOPT_POSTFIELDS(3). - While the **easy_handle** is added to a multi handle, it cannot be used by - curl_easy_perform(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -73,9 +76,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_recv.md b/docs/libcurl/curl_easy_recv.md -index fa3c8f4c6..94491b63c 100644 ---- a/docs/libcurl/curl_easy_recv.md -+++ b/docs/libcurl/curl_easy_recv.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.18.2 - --- - - # NAME -@@ -57,6 +58,8 @@ Furthermore if you wait on the socket and it tells you there is data to read, - curl_easy_recv(3) may return **CURLE_AGAIN** if the only data that was - read was for internal SSL processing, and no other data is available. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -85,9 +88,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.2. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_reset.md b/docs/libcurl/curl_easy_reset.md -index 1b09d12e7..3f4e7ae7f 100644 ---- a/docs/libcurl/curl_easy_reset.md -+++ b/docs/libcurl/curl_easy_reset.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.12.1 - --- - - # NAME -@@ -35,6 +36,8 @@ It does not change the following information kept in the handle: live - connections, the Session ID cache, the DNS cache, the cookies, the shares or - the alt-svc cache. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -49,9 +52,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.12.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_send.md b/docs/libcurl/curl_easy_send.md -index ff51eca84..04d295a45 100644 ---- a/docs/libcurl/curl_easy_send.md -+++ b/docs/libcurl/curl_easy_send.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.18.2 - --- - - # NAME -@@ -52,6 +53,8 @@ Furthermore if you wait on the socket and it tells you it is writable, - curl_easy_send(3) may return **CURLE_AGAIN** if the only data that was sent - was for internal SSL processing, and no other data could be sent. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.2. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md -index 770fdc91b..e0fe95cac 100644 ---- a/docs/libcurl/curl_easy_setopt.md -+++ b/docs/libcurl/curl_easy_setopt.md -@@ -15,6 +15,7 @@ See-also: - - curl_multi_setopt (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -36,7 +37,7 @@ appropriate options, the application can change libcurl's behavior. All - options are set with an *option* followed by a *parameter*. That parameter can - be a **long**, a **function pointer**, an **object pointer** or a - **curl_off_t**, depending on what the specific option expects. Read this --manual carefully as bad input values may cause libcurl to behave badly! You -+manual carefully as bad input values may cause libcurl to behave badly. You - can only set one option in each function call. A typical application uses many - curl_easy_setopt(3) calls in the setup phase. - -@@ -62,1030 +63,1046 @@ keep them available until libcurl no longer needed them. - The *handle* is the return code from a curl_easy_init(3) or - curl_easy_duphandle(3) call. - --# BEHAVIOR OPTIONS -+# OPTIONS - --## CURLOPT_VERBOSE -+## CURLOPT_ABSTRACT_UNIX_SOCKET - --Display verbose information. See CURLOPT_VERBOSE(3) -+Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3) - --## CURLOPT_HEADER -+## CURLOPT_ACCEPTTIMEOUT_MS - --Include the header in the body output. See CURLOPT_HEADER(3) -+Timeout for waiting for the server's connect back to be accepted. See -+CURLOPT_ACCEPTTIMEOUT_MS(3) - --## CURLOPT_NOPROGRESS -+## CURLOPT_ACCEPT_ENCODING - --Shut off the progress meter. See CURLOPT_NOPROGRESS(3) -+Accept-Encoding and automatic decompressing data. See -+CURLOPT_ACCEPT_ENCODING(3) - --## CURLOPT_NOSIGNAL -+## CURLOPT_ADDRESS_SCOPE - --Do not install signal handlers. See CURLOPT_NOSIGNAL(3) -+IPv6 scope for local addresses. See CURLOPT_ADDRESS_SCOPE(3) - --## CURLOPT_WILDCARDMATCH -+## CURLOPT_ALTSVC - --Transfer multiple files according to a filename pattern. See --CURLOPT_WILDCARDMATCH(3) -+Specify the Alt-Svc: cache filename. See CURLOPT_ALTSVC(3) - --# CALLBACK OPTIONS -+## CURLOPT_ALTSVC_CTRL - --## CURLOPT_WRITEFUNCTION -+Enable and configure Alt-Svc: treatment. See CURLOPT_ALTSVC_CTRL(3) - --Callback for writing data. See CURLOPT_WRITEFUNCTION(3) -+## CURLOPT_APPEND - --## CURLOPT_WRITEDATA -+Append to remote file. See CURLOPT_APPEND(3) - --Data pointer to pass to the write callback. See CURLOPT_WRITEDATA(3) -+## CURLOPT_AUTOREFERER - --## CURLOPT_READFUNCTION -+Automatically set Referer: header. See CURLOPT_AUTOREFERER(3) - --Callback for reading data. See CURLOPT_READFUNCTION(3) -+## CURLOPT_AWS_SIGV4 - --## CURLOPT_READDATA -+AWS HTTP V4 Signature. See CURLOPT_AWS_SIGV4(3) - --Data pointer to pass to the read callback. See CURLOPT_READDATA(3) -+## CURLOPT_BUFFERSIZE - --## CURLOPT_IOCTLFUNCTION -+Ask for alternate buffer size. See CURLOPT_BUFFERSIZE(3) - --**Deprecated option** Callback for I/O operations. --See CURLOPT_IOCTLFUNCTION(3) -+## CURLOPT_CAINFO - --## CURLOPT_IOCTLDATA -+CA cert bundle. See CURLOPT_CAINFO(3) - --**Deprecated option** Data pointer to pass to the I/O callback. --See CURLOPT_IOCTLDATA(3) -+## CURLOPT_CAINFO_BLOB - --## CURLOPT_SEEKFUNCTION -+CA cert bundle memory buffer. See CURLOPT_CAINFO_BLOB(3) - --Callback for seek operations. See CURLOPT_SEEKFUNCTION(3) -+## CURLOPT_CAPATH - --## CURLOPT_SEEKDATA -+Path to CA cert bundle. See CURLOPT_CAPATH(3) - --Data pointer to pass to the seek callback. See CURLOPT_SEEKDATA(3) -+## CURLOPT_CA_CACHE_TIMEOUT - --## CURLOPT_SOCKOPTFUNCTION -+Timeout for CA cache. See CURLOPT_CA_CACHE_TIMEOUT(3) - --Callback for sockopt operations. See CURLOPT_SOCKOPTFUNCTION(3) -+## CURLOPT_CERTINFO - --## CURLOPT_SOCKOPTDATA -+Extract certificate info. See CURLOPT_CERTINFO(3) - --Data pointer to pass to the sockopt callback. See CURLOPT_SOCKOPTDATA(3) -+## CURLOPT_CHUNK_BGN_FUNCTION - --## CURLOPT_OPENSOCKETFUNCTION -+Callback for wildcard download start of chunk. See -+CURLOPT_CHUNK_BGN_FUNCTION(3) - --Callback for socket creation. See CURLOPT_OPENSOCKETFUNCTION(3) -+## CURLOPT_CHUNK_DATA - --## CURLOPT_OPENSOCKETDATA -+Data pointer to pass to the chunk callbacks. See CURLOPT_CHUNK_DATA(3) - --Data pointer to pass to the open socket callback. See CURLOPT_OPENSOCKETDATA(3) -+## CURLOPT_CHUNK_END_FUNCTION -+ -+Callback for wildcard download end of chunk. See CURLOPT_CHUNK_END_FUNCTION(3) -+ -+## CURLOPT_CLOSESOCKETDATA -+ -+Data pointer to pass to the close socket callback. See -+CURLOPT_CLOSESOCKETDATA(3) - - ## CURLOPT_CLOSESOCKETFUNCTION - - Callback for closing socket. See CURLOPT_CLOSESOCKETFUNCTION(3) - --## CURLOPT_CLOSESOCKETDATA -+## CURLOPT_CONNECTTIMEOUT - --Data pointer to pass to the close socket callback. See CURLOPT_CLOSESOCKETDATA(3) -+Timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT(3) - --## CURLOPT_PROGRESSFUNCTION -+## CURLOPT_CONNECTTIMEOUT_MS - --**OBSOLETE** callback for progress meter. --See CURLOPT_PROGRESSFUNCTION(3) -+Millisecond timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT_MS(3) - --## CURLOPT_PROGRESSDATA -+## CURLOPT_CONNECT_ONLY - --Data pointer to pass to the progress meter callback. See CURLOPT_PROGRESSDATA(3) -+Only connect, nothing else. See CURLOPT_CONNECT_ONLY(3) - --## CURLOPT_XFERINFOFUNCTION -+## CURLOPT_CONNECT_TO - --Callback for progress meter. See CURLOPT_XFERINFOFUNCTION(3) -+Connect to a specific host and port. See CURLOPT_CONNECT_TO(3) - --## CURLOPT_XFERINFODATA -+## CURLOPT_CONV_FROM_NETWORK_FUNCTION - --Data pointer to pass to the progress meter callback. See CURLOPT_XFERINFODATA(3) -+**OBSOLETE** Callback for code base conversion. -+See CURLOPT_CONV_FROM_NETWORK_FUNCTION(3) - --## CURLOPT_HEADERFUNCTION -+## CURLOPT_CONV_FROM_UTF8_FUNCTION - --Callback for writing received headers. See CURLOPT_HEADERFUNCTION(3) -+**OBSOLETE** Callback for code base conversion. -+See CURLOPT_CONV_FROM_UTF8_FUNCTION(3) - --## CURLOPT_HEADERDATA -+## CURLOPT_CONV_TO_NETWORK_FUNCTION - --Data pointer to pass to the header callback. See CURLOPT_HEADERDATA(3) -+**OBSOLETE** Callback for code base conversion. -+See CURLOPT_CONV_TO_NETWORK_FUNCTION(3) - --## CURLOPT_DEBUGFUNCTION -+## CURLOPT_COOKIE - --Callback for debug information. See CURLOPT_DEBUGFUNCTION(3) -+Cookie(s) to send. See CURLOPT_COOKIE(3) - --## CURLOPT_DEBUGDATA -+## CURLOPT_COOKIEFILE - --Data pointer to pass to the debug callback. See CURLOPT_DEBUGDATA(3) -+File to read cookies from. See CURLOPT_COOKIEFILE(3) - --## CURLOPT_SSL_CTX_FUNCTION -+## CURLOPT_COOKIEJAR - --Callback for SSL context logic. See CURLOPT_SSL_CTX_FUNCTION(3) -+File to write cookies to. See CURLOPT_COOKIEJAR(3) - --## CURLOPT_SSL_CTX_DATA -+## CURLOPT_COOKIELIST - --Data pointer to pass to the SSL context callback. See CURLOPT_SSL_CTX_DATA(3) -+Add or control cookies. See CURLOPT_COOKIELIST(3) - --## CURLOPT_CONV_TO_NETWORK_FUNCTION -+## CURLOPT_COOKIESESSION - --**OBSOLETE** Callback for code base conversion. --See CURLOPT_CONV_TO_NETWORK_FUNCTION(3) -+Start a new cookie session. See CURLOPT_COOKIESESSION(3) - --## CURLOPT_CONV_FROM_NETWORK_FUNCTION -+## CURLOPT_COPYPOSTFIELDS - --**OBSOLETE** Callback for code base conversion. --See CURLOPT_CONV_FROM_NETWORK_FUNCTION(3) -+Send a POST with this data - and copy it. See CURLOPT_COPYPOSTFIELDS(3) - --## CURLOPT_CONV_FROM_UTF8_FUNCTION -+## CURLOPT_CRLF - --**OBSOLETE** Callback for code base conversion. --See CURLOPT_CONV_FROM_UTF8_FUNCTION(3) -+Convert newlines. See CURLOPT_CRLF(3) - --## CURLOPT_INTERLEAVEFUNCTION -+## CURLOPT_CRLFILE - --Callback for RTSP interleaved data. See CURLOPT_INTERLEAVEFUNCTION(3) -+Certificate Revocation List. See CURLOPT_CRLFILE(3) - --## CURLOPT_INTERLEAVEDATA -+## CURLOPT_CURLU - --Data pointer to pass to the RTSP interleave callback. See CURLOPT_INTERLEAVEDATA(3) -+Set URL to work on with a URL handle. See CURLOPT_CURLU(3) - --## CURLOPT_CHUNK_BGN_FUNCTION -+## CURLOPT_CUSTOMREQUEST - --Callback for wildcard download start of chunk. See CURLOPT_CHUNK_BGN_FUNCTION(3) -+Custom request/method. See CURLOPT_CUSTOMREQUEST(3) - --## CURLOPT_CHUNK_END_FUNCTION -+## CURLOPT_DEBUGDATA - --Callback for wildcard download end of chunk. See CURLOPT_CHUNK_END_FUNCTION(3) -+Data pointer to pass to the debug callback. See CURLOPT_DEBUGDATA(3) - --## CURLOPT_CHUNK_DATA -+## CURLOPT_DEBUGFUNCTION - --Data pointer to pass to the chunk callbacks. See CURLOPT_CHUNK_DATA(3) -+Callback for debug information. See CURLOPT_DEBUGFUNCTION(3) - --## CURLOPT_FNMATCH_FUNCTION -+## CURLOPT_DEFAULT_PROTOCOL - --Callback for wildcard matching. See CURLOPT_FNMATCH_FUNCTION(3) -+Default protocol. See CURLOPT_DEFAULT_PROTOCOL(3) - --## CURLOPT_FNMATCH_DATA -+## CURLOPT_DIRLISTONLY - --Data pointer to pass to the wildcard matching callback. See CURLOPT_FNMATCH_DATA(3) -+List only. See CURLOPT_DIRLISTONLY(3) - --## CURLOPT_SUPPRESS_CONNECT_HEADERS -+## CURLOPT_DISALLOW_USERNAME_IN_URL - --Suppress proxy CONNECT response headers from user callbacks. See --CURLOPT_SUPPRESS_CONNECT_HEADERS(3) -+Do not allow username in URL. See CURLOPT_DISALLOW_USERNAME_IN_URL(3) - --## CURLOPT_RESOLVER_START_FUNCTION -+## CURLOPT_DNS_CACHE_TIMEOUT - --Callback to be called before a new resolve request is started. See --CURLOPT_RESOLVER_START_FUNCTION(3) -+Timeout for DNS cache. See CURLOPT_DNS_CACHE_TIMEOUT(3) - --## CURLOPT_RESOLVER_START_DATA -+## CURLOPT_DNS_INTERFACE - --Data pointer to pass to resolver start callback. See CURLOPT_RESOLVER_START_DATA(3) -+Bind name resolves to this interface. See CURLOPT_DNS_INTERFACE(3) - --## CURLOPT_PREREQFUNCTION -+## CURLOPT_DNS_LOCAL_IP4 - --Callback to be called after a connection is established but before a request --is made on that connection. See CURLOPT_PREREQFUNCTION(3) -+Bind name resolves to this IP4 address. See CURLOPT_DNS_LOCAL_IP4(3) - --## CURLOPT_PREREQDATA -+## CURLOPT_DNS_LOCAL_IP6 - --Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See --CURLOPT_PREREQDATA(3) -+Bind name resolves to this IP6 address. See CURLOPT_DNS_LOCAL_IP6(3) - --# ERROR OPTIONS -+## CURLOPT_DNS_SERVERS - --## CURLOPT_ERRORBUFFER -+Preferred DNS servers. See CURLOPT_DNS_SERVERS(3) - --Error message buffer. See CURLOPT_ERRORBUFFER(3) -+## CURLOPT_DNS_SHUFFLE_ADDRESSES - --## CURLOPT_STDERR -+Shuffle addresses before use. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3) - --stderr replacement stream. See CURLOPT_STDERR(3) -+## CURLOPT_DNS_USE_GLOBAL_CACHE - --## CURLOPT_FAILONERROR -+**OBSOLETE** Enable global DNS cache. See CURLOPT_DNS_USE_GLOBAL_CACHE(3) - --Fail on HTTP 4xx errors. CURLOPT_FAILONERROR(3) -+## CURLOPT_DOH_SSL_VERIFYHOST - --## CURLOPT_KEEP_SENDING_ON_ERROR -+Verify the hostname in the DoH (DNS-over-HTTPS) SSL certificate. See -+CURLOPT_DOH_SSL_VERIFYHOST(3) - --Keep sending on HTTP \>= 300 errors. CURLOPT_KEEP_SENDING_ON_ERROR(3) -+## CURLOPT_DOH_SSL_VERIFYPEER - --# NETWORK OPTIONS -+Verify the DoH (DNS-over-HTTPS) SSL certificate. See -+CURLOPT_DOH_SSL_VERIFYPEER(3) - --## CURLOPT_URL -+## CURLOPT_DOH_SSL_VERIFYSTATUS - --URL to work on. See CURLOPT_URL(3) -+Verify the DoH (DNS-over-HTTPS) SSL certificate's status. See -+CURLOPT_DOH_SSL_VERIFYSTATUS(3) - --## CURLOPT_PATH_AS_IS -+## CURLOPT_DOH_URL - --Disable squashing /../ and /./ sequences in the path. See CURLOPT_PATH_AS_IS(3) -+Use this DoH server for name resolves. See CURLOPT_DOH_URL(3) - --## CURLOPT_PROTOCOLS -+## CURLOPT_ECH - --**Deprecated option** Allowed protocols. See CURLOPT_PROTOCOLS(3) -+Set the configuration for ECH. See CURLOPT_ECH(3) - --## CURLOPT_PROTOCOLS_STR -+## CURLOPT_EGDSOCKET - --Allowed protocols. See CURLOPT_PROTOCOLS_STR(3) -+**OBSOLETE** Identify EGD socket for entropy. See CURLOPT_EGDSOCKET(3) - --## CURLOPT_REDIR_PROTOCOLS -+## CURLOPT_ERRORBUFFER - --**Deprecated option** Protocols to allow redirects to. See --CURLOPT_REDIR_PROTOCOLS(3) -+Error message buffer. See CURLOPT_ERRORBUFFER(3) - --## CURLOPT_REDIR_PROTOCOLS_STR -+## CURLOPT_EXPECT_100_TIMEOUT_MS - --Protocols to allow redirects to. See CURLOPT_REDIR_PROTOCOLS_STR(3) -+100-continue timeout. See CURLOPT_EXPECT_100_TIMEOUT_MS(3) - --## CURLOPT_DEFAULT_PROTOCOL -+## CURLOPT_FAILONERROR - --Default protocol. See CURLOPT_DEFAULT_PROTOCOL(3) -+Fail on HTTP 4xx errors. CURLOPT_FAILONERROR(3) - --## CURLOPT_PROXY -+## CURLOPT_FILETIME - --Proxy to use. See CURLOPT_PROXY(3) -+Request file modification date and time. See CURLOPT_FILETIME(3) - --## CURLOPT_PRE_PROXY -+## CURLOPT_FNMATCH_DATA - --Socks proxy to use. See CURLOPT_PRE_PROXY(3) -+Data pointer to pass to the wildcard matching callback. See -+CURLOPT_FNMATCH_DATA(3) - --## CURLOPT_PROXYPORT -+## CURLOPT_FNMATCH_FUNCTION - --Proxy port to use. See CURLOPT_PROXYPORT(3) -+Callback for wildcard matching. See CURLOPT_FNMATCH_FUNCTION(3) - --## CURLOPT_PROXYTYPE -+## CURLOPT_FOLLOWLOCATION - --Proxy type. See CURLOPT_PROXYTYPE(3) -+Follow HTTP redirects. See CURLOPT_FOLLOWLOCATION(3) - --## CURLOPT_NOPROXY -+## CURLOPT_FORBID_REUSE - --Filter out hosts from proxy use. CURLOPT_NOPROXY(3) -+Prevent subsequent connections from reusing this. See CURLOPT_FORBID_REUSE(3) - --## CURLOPT_HTTPPROXYTUNNEL -+## CURLOPT_FRESH_CONNECT - --Tunnel through the HTTP proxy. CURLOPT_HTTPPROXYTUNNEL(3) -+Use a new connection. CURLOPT_FRESH_CONNECT(3) - --## CURLOPT_CONNECT_TO -+## CURLOPT_FTPPORT - --Connect to a specific host and port. See CURLOPT_CONNECT_TO(3) -+Use active FTP. See CURLOPT_FTPPORT(3) - --## CURLOPT_SOCKS5_AUTH -+## CURLOPT_FTPSSLAUTH - --Socks5 authentication methods. See CURLOPT_SOCKS5_AUTH(3) -+Control how to do TLS. See CURLOPT_FTPSSLAUTH(3) - --## CURLOPT_SOCKS5_GSSAPI_SERVICE -+## CURLOPT_FTP_ACCOUNT - --**Deprecated option** Socks5 GSSAPI service name. --See CURLOPT_SOCKS5_GSSAPI_SERVICE(3) -+Send ACCT command. See CURLOPT_FTP_ACCOUNT(3) - --## CURLOPT_SOCKS5_GSSAPI_NEC -+## CURLOPT_FTP_ALTERNATIVE_TO_USER - --Socks5 GSSAPI NEC mode. See CURLOPT_SOCKS5_GSSAPI_NEC(3) -+Alternative to USER. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3) - --## CURLOPT_PROXY_SERVICE_NAME -+## CURLOPT_FTP_CREATE_MISSING_DIRS - --Proxy authentication service name. CURLOPT_PROXY_SERVICE_NAME(3) -+Create missing directories on the remote server. See -+CURLOPT_FTP_CREATE_MISSING_DIRS(3) - --## CURLOPT_HAPROXYPROTOCOL -+## CURLOPT_FTP_FILEMETHOD - --Send an HAProxy PROXY protocol v1 header. See CURLOPT_HAPROXYPROTOCOL(3) -+Specify how to reach files. See CURLOPT_FTP_FILEMETHOD(3) - --## CURLOPT_HAPROXY_CLIENT_IP -+## CURLOPT_FTP_SKIP_PASV_IP - --Spoof the client IP in an HAProxy PROXY protocol v1 header. See --CURLOPT_HAPROXY_CLIENT_IP(3) -+Ignore the IP address in the PASV response. See CURLOPT_FTP_SKIP_PASV_IP(3) - --## CURLOPT_SERVICE_NAME -+## CURLOPT_FTP_SSL_CCC - --Authentication service name. CURLOPT_SERVICE_NAME(3) -+Back to non-TLS again after authentication. See CURLOPT_FTP_SSL_CCC(3) - --## CURLOPT_INTERFACE -+## CURLOPT_FTP_USE_EPRT - --Bind connection locally to this. See CURLOPT_INTERFACE(3) -+Use EPRT. See CURLOPT_FTP_USE_EPRT(3) - --## CURLOPT_LOCALPORT -+## CURLOPT_FTP_USE_EPSV - --Bind connection locally to this port. See CURLOPT_LOCALPORT(3) -+Use EPSV. See CURLOPT_FTP_USE_EPSV(3) - --## CURLOPT_LOCALPORTRANGE -+## CURLOPT_FTP_USE_PRET - --Bind connection locally to port range. See CURLOPT_LOCALPORTRANGE(3) -+Use PRET. See CURLOPT_FTP_USE_PRET(3) - --## CURLOPT_DNS_CACHE_TIMEOUT -+## CURLOPT_GSSAPI_DELEGATION - --Timeout for DNS cache. See CURLOPT_DNS_CACHE_TIMEOUT(3) -+Disable GSS-API delegation. See CURLOPT_GSSAPI_DELEGATION(3) - --## CURLOPT_DNS_USE_GLOBAL_CACHE -+## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS - --**OBSOLETE** Enable global DNS cache. --See CURLOPT_DNS_USE_GLOBAL_CACHE(3) -+Timeout for happy eyeballs. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3) - --## CURLOPT_DOH_URL -+## CURLOPT_HAPROXYPROTOCOL - --Use this DoH server for name resolves. See CURLOPT_DOH_URL(3) -+Send an HAProxy PROXY protocol v1 header. See CURLOPT_HAPROXYPROTOCOL(3) - --## CURLOPT_BUFFERSIZE -+## CURLOPT_HAPROXY_CLIENT_IP - --Ask for alternate buffer size. See CURLOPT_BUFFERSIZE(3) -+Spoof the client IP in an HAProxy PROXY protocol v1 header. See -+CURLOPT_HAPROXY_CLIENT_IP(3) - --## CURLOPT_PORT -+## CURLOPT_HEADER - --Port number to connect to. See CURLOPT_PORT(3) -+Include the header in the body output. See CURLOPT_HEADER(3) - --## CURLOPT_TCP_FASTOPEN -+## CURLOPT_HEADERDATA - --Enable TCP Fast Open. See CURLOPT_TCP_FASTOPEN(3) -+Data pointer to pass to the header callback. See CURLOPT_HEADERDATA(3) - --## CURLOPT_TCP_NODELAY -+## CURLOPT_HEADERFUNCTION - --Disable the Nagle algorithm. See CURLOPT_TCP_NODELAY(3) -+Callback for writing received headers. See CURLOPT_HEADERFUNCTION(3) - --## CURLOPT_ADDRESS_SCOPE -+## CURLOPT_HEADEROPT - --IPv6 scope for local addresses. See CURLOPT_ADDRESS_SCOPE(3) -+Control custom headers. See CURLOPT_HEADEROPT(3) - --## CURLOPT_TCP_KEEPALIVE -+## CURLOPT_HSTS - --Enable TCP keep-alive. See CURLOPT_TCP_KEEPALIVE(3) -+Set HSTS cache file. See CURLOPT_HSTS(3) - --## CURLOPT_TCP_KEEPIDLE -+## CURLOPT_HSTSREADDATA - --Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3) -+Pass pointer to the HSTS read callback. See CURLOPT_HSTSREADDATA(3) - --## CURLOPT_TCP_KEEPINTVL -+## CURLOPT_HSTSREADFUNCTION - --Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3) -+Set HSTS read callback. See CURLOPT_HSTSREADFUNCTION(3) - --## CURLOPT_UNIX_SOCKET_PATH -+## CURLOPT_HSTSWRITEDATA - --Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3) -+Pass pointer to the HSTS write callback. See CURLOPT_HSTSWRITEDATA(3) - --## CURLOPT_ABSTRACT_UNIX_SOCKET -+## CURLOPT_HSTSWRITEFUNCTION - --Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3) -+Set HSTS write callback. See CURLOPT_HSTSWRITEFUNCTION(3) - --# NAMES and PASSWORDS OPTIONS (Authentication) -+## CURLOPT_HSTS_CTRL - --## CURLOPT_NETRC -+Enable HSTS. See CURLOPT_HSTS_CTRL(3) - --Enable .netrc parsing. See CURLOPT_NETRC(3) -+## CURLOPT_HTTP09_ALLOWED - --## CURLOPT_NETRC_FILE -+Allow HTTP/0.9 responses. CURLOPT_HTTP09_ALLOWED(3) - --.netrc filename. See CURLOPT_NETRC_FILE(3) -+## CURLOPT_HTTP200ALIASES - --## CURLOPT_USERPWD -+Alternative versions of 200 OK. See CURLOPT_HTTP200ALIASES(3) - --Username and password. See CURLOPT_USERPWD(3) -+## CURLOPT_HTTPAUTH - --## CURLOPT_PROXYUSERPWD -+HTTP server authentication methods. See CURLOPT_HTTPAUTH(3) - --Proxy username and password. See CURLOPT_PROXYUSERPWD(3) -+## CURLOPT_HTTPGET - --## CURLOPT_USERNAME -+Do an HTTP GET request. See CURLOPT_HTTPGET(3) - --Username. See CURLOPT_USERNAME(3) -+## CURLOPT_HTTPHEADER - --## CURLOPT_PASSWORD -+Custom HTTP headers. See CURLOPT_HTTPHEADER(3) - --Password. See CURLOPT_PASSWORD(3) -+## CURLOPT_HTTPPOST - --## CURLOPT_LOGIN_OPTIONS -+**Deprecated option** Multipart formpost HTTP POST. -+See CURLOPT_HTTPPOST(3) - --Login options. See CURLOPT_LOGIN_OPTIONS(3) -+## CURLOPT_HTTPPROXYTUNNEL - --## CURLOPT_PROXYUSERNAME -+Tunnel through the HTTP proxy. CURLOPT_HTTPPROXYTUNNEL(3) - --Proxy username. See CURLOPT_PROXYUSERNAME(3) -+## CURLOPT_HTTP_CONTENT_DECODING - --## CURLOPT_PROXYPASSWORD -+Disable Content decoding. See CURLOPT_HTTP_CONTENT_DECODING(3) - --Proxy password. See CURLOPT_PROXYPASSWORD(3) -+## CURLOPT_HTTP_TRANSFER_DECODING - --## CURLOPT_HTTPAUTH -+Disable Transfer decoding. See CURLOPT_HTTP_TRANSFER_DECODING(3) - --HTTP server authentication methods. See CURLOPT_HTTPAUTH(3) -+## CURLOPT_HTTP_VERSION - --## CURLOPT_TLSAUTH_USERNAME -+HTTP version to use. CURLOPT_HTTP_VERSION(3) - --TLS authentication username. See CURLOPT_TLSAUTH_USERNAME(3) -+## CURLOPT_IGNORE_CONTENT_LENGTH - --## CURLOPT_PROXY_TLSAUTH_USERNAME -+Ignore Content-Length. See CURLOPT_IGNORE_CONTENT_LENGTH(3) - --Proxy TLS authentication username. See CURLOPT_PROXY_TLSAUTH_USERNAME(3) -+## CURLOPT_INFILESIZE - --## CURLOPT_TLSAUTH_PASSWORD -+Size of file to send. CURLOPT_INFILESIZE(3) - --TLS authentication password. See CURLOPT_TLSAUTH_PASSWORD(3) -+## CURLOPT_INFILESIZE_LARGE - --## CURLOPT_PROXY_TLSAUTH_PASSWORD -+Size of file to send. CURLOPT_INFILESIZE_LARGE(3) - --Proxy TLS authentication password. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3) -+## CURLOPT_INTERFACE - --## CURLOPT_TLSAUTH_TYPE -+Bind connection locally to this. See CURLOPT_INTERFACE(3) - --TLS authentication methods. See CURLOPT_TLSAUTH_TYPE(3) -+## CURLOPT_INTERLEAVEDATA - --## CURLOPT_PROXY_TLSAUTH_TYPE -+Data pointer to pass to the RTSP interleave callback. See -+CURLOPT_INTERLEAVEDATA(3) - --Proxy TLS authentication methods. See CURLOPT_PROXY_TLSAUTH_TYPE(3) -+## CURLOPT_INTERLEAVEFUNCTION - --## CURLOPT_PROXYAUTH -+Callback for RTSP interleaved data. See CURLOPT_INTERLEAVEFUNCTION(3) - --HTTP proxy authentication methods. See CURLOPT_PROXYAUTH(3) -+## CURLOPT_IOCTLDATA - --## CURLOPT_SASL_AUTHZID -+**Deprecated option** Data pointer to pass to the I/O callback. -+See CURLOPT_IOCTLDATA(3) - --SASL authorization identity (identity to act as). See CURLOPT_SASL_AUTHZID(3) -+## CURLOPT_IOCTLFUNCTION - --## CURLOPT_SASL_IR -+**Deprecated option** Callback for I/O operations. -+See CURLOPT_IOCTLFUNCTION(3) - --Enable SASL initial response. See CURLOPT_SASL_IR(3) -+## CURLOPT_IPRESOLVE - --## CURLOPT_XOAUTH2_BEARER -+IP version to use. See CURLOPT_IPRESOLVE(3) - --OAuth2 bearer token. See CURLOPT_XOAUTH2_BEARER(3) -+## CURLOPT_ISSUERCERT - --## CURLOPT_DISALLOW_USERNAME_IN_URL -+Issuer certificate. See CURLOPT_ISSUERCERT(3) - --Do not allow username in URL. See CURLOPT_DISALLOW_USERNAME_IN_URL(3) -+## CURLOPT_ISSUERCERT_BLOB - --# HTTP OPTIONS -+Issuer certificate memory buffer. See CURLOPT_ISSUERCERT_BLOB(3) - --## CURLOPT_AUTOREFERER -+## CURLOPT_KEEP_SENDING_ON_ERROR - --Automatically set Referer: header. See CURLOPT_AUTOREFERER(3) -+Keep sending on HTTP \>= 300 errors. CURLOPT_KEEP_SENDING_ON_ERROR(3) - --## CURLOPT_ACCEPT_ENCODING -+## CURLOPT_KEYPASSWD - --Accept-Encoding and automatic decompressing data. See CURLOPT_ACCEPT_ENCODING(3) -+Client key password. See CURLOPT_KEYPASSWD(3) - --## CURLOPT_TRANSFER_ENCODING -+## CURLOPT_KRBLEVEL - --Request Transfer-Encoding. See CURLOPT_TRANSFER_ENCODING(3) -+Kerberos security level. See CURLOPT_KRBLEVEL(3) -+ -+## CURLOPT_LOCALPORT -+ -+Bind connection locally to this port. See CURLOPT_LOCALPORT(3) -+ -+## CURLOPT_LOCALPORTRANGE -+ -+Bind connection locally to port range. See CURLOPT_LOCALPORTRANGE(3) - --## CURLOPT_FOLLOWLOCATION -+## CURLOPT_LOGIN_OPTIONS - --Follow HTTP redirects. See CURLOPT_FOLLOWLOCATION(3) -+Login options. See CURLOPT_LOGIN_OPTIONS(3) - --## CURLOPT_UNRESTRICTED_AUTH -+## CURLOPT_LOW_SPEED_LIMIT - --Do not restrict authentication to original host. CURLOPT_UNRESTRICTED_AUTH(3) -+Low speed limit to abort transfer. See CURLOPT_LOW_SPEED_LIMIT(3) - --## CURLOPT_MAXREDIRS -+## CURLOPT_LOW_SPEED_TIME - --Maximum number of redirects to follow. See CURLOPT_MAXREDIRS(3) -+Time to be below the speed to trigger low speed abort. See -+CURLOPT_LOW_SPEED_TIME(3) - --## CURLOPT_POSTREDIR -+## CURLOPT_MAIL_AUTH - --How to act on redirects after POST. See CURLOPT_POSTREDIR(3) -+Authentication address. See CURLOPT_MAIL_AUTH(3) - --## CURLOPT_PUT -+## CURLOPT_MAIL_FROM - --**Deprecated option** Issue an HTTP PUT request. See CURLOPT_PUT(3) -+Address of the sender. See CURLOPT_MAIL_FROM(3) - --## CURLOPT_POST -+## CURLOPT_MAIL_RCPT - --Issue an HTTP POST request. See CURLOPT_POST(3) -+Address of the recipients. See CURLOPT_MAIL_RCPT(3) - --## CURLOPT_POSTFIELDS -+## CURLOPT_MAIL_RCPT_ALLOWFAILS - --Send a POST with this data. See CURLOPT_POSTFIELDS(3) -+Allow RCPT TO command to fail for some recipients. See -+CURLOPT_MAIL_RCPT_ALLOWFAILS(3) - --## CURLOPT_POSTFIELDSIZE -+## CURLOPT_MAXAGE_CONN - --The POST data is this big. See CURLOPT_POSTFIELDSIZE(3) -+Limit the age (idle time) of connections for reuse. See CURLOPT_MAXAGE_CONN(3) - --## CURLOPT_POSTFIELDSIZE_LARGE -+## CURLOPT_MAXCONNECTS - --The POST data is this big. See CURLOPT_POSTFIELDSIZE_LARGE(3) -+Maximum number of connections in the connection pool. See -+CURLOPT_MAXCONNECTS(3) - --## CURLOPT_COPYPOSTFIELDS -+## CURLOPT_MAXFILESIZE - --Send a POST with this data - and copy it. See CURLOPT_COPYPOSTFIELDS(3) -+Maximum file size to get. See CURLOPT_MAXFILESIZE(3) - --## CURLOPT_HTTPPOST -+## CURLOPT_MAXFILESIZE_LARGE - --**Deprecated option** Multipart formpost HTTP POST. --See CURLOPT_HTTPPOST(3) -+Maximum file size to get. See CURLOPT_MAXFILESIZE_LARGE(3) - --## CURLOPT_REFERER -+## CURLOPT_MAXLIFETIME_CONN - --Referer: header. See CURLOPT_REFERER(3) -+Limit the age (since creation) of connections for reuse. See -+CURLOPT_MAXLIFETIME_CONN(3) - --## CURLOPT_USERAGENT -+## CURLOPT_MAXREDIRS - --User-Agent: header. See CURLOPT_USERAGENT(3) -+Maximum number of redirects to follow. See CURLOPT_MAXREDIRS(3) - --## CURLOPT_HTTPHEADER -+## CURLOPT_MAX_RECV_SPEED_LARGE - --Custom HTTP headers. See CURLOPT_HTTPHEADER(3) -+Cap the download speed to this. See CURLOPT_MAX_RECV_SPEED_LARGE(3) - --## CURLOPT_HEADEROPT -+## CURLOPT_MAX_SEND_SPEED_LARGE - --Control custom headers. See CURLOPT_HEADEROPT(3) -+Cap the upload speed to this. See CURLOPT_MAX_SEND_SPEED_LARGE(3) - --## CURLOPT_PROXYHEADER -+## CURLOPT_MIMEPOST - --Custom HTTP headers sent to proxy. See CURLOPT_PROXYHEADER(3) -+Post/send MIME data. See CURLOPT_MIMEPOST(3) - --## CURLOPT_HTTP200ALIASES -+## CURLOPT_MIME_OPTIONS - --Alternative versions of 200 OK. See CURLOPT_HTTP200ALIASES(3) -+Set MIME option flags. See CURLOPT_MIME_OPTIONS(3) - --## CURLOPT_COOKIE -+## CURLOPT_NETRC - --Cookie(s) to send. See CURLOPT_COOKIE(3) -+Enable .netrc parsing. See CURLOPT_NETRC(3) - --## CURLOPT_COOKIEFILE -+## CURLOPT_NETRC_FILE - --File to read cookies from. See CURLOPT_COOKIEFILE(3) -+.netrc filename. See CURLOPT_NETRC_FILE(3) - --## CURLOPT_COOKIEJAR -+## CURLOPT_NEW_DIRECTORY_PERMS - --File to write cookies to. See CURLOPT_COOKIEJAR(3) -+Mode for creating new remote directories. See CURLOPT_NEW_DIRECTORY_PERMS(3) - --## CURLOPT_COOKIESESSION -+## CURLOPT_NEW_FILE_PERMS - --Start a new cookie session. See CURLOPT_COOKIESESSION(3) -+Mode for creating new remote files. See CURLOPT_NEW_FILE_PERMS(3) - --## CURLOPT_COOKIELIST -+## CURLOPT_NOBODY - --Add or control cookies. See CURLOPT_COOKIELIST(3) -+Do not get the body contents. See CURLOPT_NOBODY(3) - --## CURLOPT_ALTSVC -+## CURLOPT_NOPROGRESS - --Specify the Alt-Svc: cache filename. See CURLOPT_ALTSVC(3) -+Shut off the progress meter. See CURLOPT_NOPROGRESS(3) - --## CURLOPT_ALTSVC_CTRL -+## CURLOPT_NOPROXY - --Enable and configure Alt-Svc: treatment. See CURLOPT_ALTSVC_CTRL(3) -+Filter out hosts from proxy use. CURLOPT_NOPROXY(3) - --## CURLOPT_HSTS -+## CURLOPT_NOSIGNAL - --Set HSTS cache file. See CURLOPT_HSTS(3) -+Do not install signal handlers. See CURLOPT_NOSIGNAL(3) - --## CURLOPT_HSTS_CTRL -+## CURLOPT_OPENSOCKETDATA - --Enable HSTS. See CURLOPT_HSTS_CTRL(3) -+Data pointer to pass to the open socket callback. See CURLOPT_OPENSOCKETDATA(3) - --## CURLOPT_HSTSREADFUNCTION -+## CURLOPT_OPENSOCKETFUNCTION - --Set HSTS read callback. See CURLOPT_HSTSREADFUNCTION(3) -+Callback for socket creation. See CURLOPT_OPENSOCKETFUNCTION(3) - --## CURLOPT_HSTSREADDATA -+## CURLOPT_PASSWORD - --Pass pointer to the HSTS read callback. See CURLOPT_HSTSREADDATA(3) -+Password. See CURLOPT_PASSWORD(3) - --## CURLOPT_HSTSWRITEFUNCTION -+## CURLOPT_PATH_AS_IS - --Set HSTS write callback. See CURLOPT_HSTSWRITEFUNCTION(3) -+Disable squashing /../ and /./ sequences in the path. See CURLOPT_PATH_AS_IS(3) - --## CURLOPT_HSTSWRITEDATA -+## CURLOPT_PINNEDPUBLICKEY - --Pass pointer to the HSTS write callback. See CURLOPT_HSTSWRITEDATA(3) -+Set pinned SSL public key . See CURLOPT_PINNEDPUBLICKEY(3) - --## CURLOPT_HTTPGET -+## CURLOPT_PIPEWAIT - --Do an HTTP GET request. See CURLOPT_HTTPGET(3) -+Wait on connection to pipeline on it. See CURLOPT_PIPEWAIT(3) - --## CURLOPT_REQUEST_TARGET -+## CURLOPT_PORT - --Set the request target. CURLOPT_REQUEST_TARGET(3) -+Port number to connect to. See CURLOPT_PORT(3) - --## CURLOPT_HTTP_VERSION -+## CURLOPT_POST - --HTTP version to use. CURLOPT_HTTP_VERSION(3) -+Make an HTTP POST. See CURLOPT_POST(3) - --## CURLOPT_HTTP09_ALLOWED -+## CURLOPT_POSTFIELDSIZE - --Allow HTTP/0.9 responses. CURLOPT_HTTP09_ALLOWED(3) -+The POST data is this big. See CURLOPT_POSTFIELDSIZE(3) - --## CURLOPT_IGNORE_CONTENT_LENGTH -+## CURLOPT_POSTFIELDSIZE_LARGE - --Ignore Content-Length. See CURLOPT_IGNORE_CONTENT_LENGTH(3) -+The POST data is this big. See CURLOPT_POSTFIELDSIZE_LARGE(3) - --## CURLOPT_HTTP_CONTENT_DECODING -+## CURLOPT_POSTQUOTE - --Disable Content decoding. See CURLOPT_HTTP_CONTENT_DECODING(3) -+Commands to run after transfer. See CURLOPT_POSTQUOTE(3) - --## CURLOPT_HTTP_TRANSFER_DECODING -+## CURLOPT_POSTREDIR - --Disable Transfer decoding. See CURLOPT_HTTP_TRANSFER_DECODING(3) -+How to act on redirects after POST. See CURLOPT_POSTREDIR(3) - --## CURLOPT_EXPECT_100_TIMEOUT_MS -+## CURLOPT_PREQUOTE - --100-continue timeout. See CURLOPT_EXPECT_100_TIMEOUT_MS(3) -+Commands to run just before transfer. See CURLOPT_PREQUOTE(3) - --## CURLOPT_TRAILERFUNCTION -+## CURLOPT_PREREQDATA - --Set callback for sending trailing headers. See --CURLOPT_TRAILERFUNCTION(3) -+Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See -+CURLOPT_PREREQDATA(3) - --## CURLOPT_TRAILERDATA -+## CURLOPT_PREREQFUNCTION - --Custom pointer passed to the trailing headers callback. See --CURLOPT_TRAILERDATA(3) -+Callback to be called after a connection is established but before a request -+is made on that connection. See CURLOPT_PREREQFUNCTION(3) - --## CURLOPT_PIPEWAIT -+## CURLOPT_PRE_PROXY - --Wait on connection to pipeline on it. See CURLOPT_PIPEWAIT(3) -+Socks proxy to use. See CURLOPT_PRE_PROXY(3) - --## CURLOPT_STREAM_DEPENDS -+## CURLOPT_PRIVATE - --This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3) -+Private pointer to store. See CURLOPT_PRIVATE(3) - --## CURLOPT_STREAM_DEPENDS_E -+## CURLOPT_PROGRESSDATA - --This HTTP/2 stream depends on another exclusively. See --CURLOPT_STREAM_DEPENDS_E(3) -+Data pointer to pass to the progress meter callback. See -+CURLOPT_PROGRESSDATA(3) - --## CURLOPT_STREAM_WEIGHT -+## CURLOPT_PROGRESSFUNCTION - --Set this HTTP/2 stream's weight. See CURLOPT_STREAM_WEIGHT(3) -+**OBSOLETE** callback for progress meter. See CURLOPT_PROGRESSFUNCTION(3) - --# SMTP OPTIONS -+## CURLOPT_PROTOCOLS - --## CURLOPT_MAIL_FROM -+**Deprecated option** Allowed protocols. See CURLOPT_PROTOCOLS(3) - --Address of the sender. See CURLOPT_MAIL_FROM(3) -+## CURLOPT_PROTOCOLS_STR - --## CURLOPT_MAIL_RCPT -+Allowed protocols. See CURLOPT_PROTOCOLS_STR(3) - --Address of the recipients. See CURLOPT_MAIL_RCPT(3) -+## CURLOPT_PROXY - --## CURLOPT_MAIL_AUTH -+Proxy to use. See CURLOPT_PROXY(3) - --Authentication address. See CURLOPT_MAIL_AUTH(3) -+## CURLOPT_PROXYAUTH - --## CURLOPT_MAIL_RCPT_ALLOWFAILS -+HTTP proxy authentication methods. See CURLOPT_PROXYAUTH(3) - --Allow RCPT TO command to fail for some recipients. See --CURLOPT_MAIL_RCPT_ALLOWFAILS(3) -+## CURLOPT_PROXYHEADER - --# TFTP OPTIONS -+Custom HTTP headers sent to proxy. See CURLOPT_PROXYHEADER(3) - --## CURLOPT_TFTP_BLKSIZE -+## CURLOPT_PROXYPASSWORD - --TFTP block size. See CURLOPT_TFTP_BLKSIZE(3) -+Proxy password. See CURLOPT_PROXYPASSWORD(3) - --## CURLOPT_TFTP_NO_OPTIONS -+## CURLOPT_PROXYPORT - --Do not send TFTP options requests. See CURLOPT_TFTP_NO_OPTIONS(3) -+Proxy port to use. See CURLOPT_PROXYPORT(3) - --# FTP OPTIONS -+## CURLOPT_PROXYTYPE - --## CURLOPT_FTPPORT -+Proxy type. See CURLOPT_PROXYTYPE(3) - --Use active FTP. See CURLOPT_FTPPORT(3) -+## CURLOPT_PROXYUSERNAME -+Proxy username. See CURLOPT_PROXYUSERNAME(3) - --## CURLOPT_QUOTE -+## CURLOPT_PROXYUSERPWD - --Commands to run before transfer. See CURLOPT_QUOTE(3) -+Proxy username and password. See CURLOPT_PROXYUSERPWD(3) - --## CURLOPT_POSTQUOTE -+## CURLOPT_PROXY_CAINFO - --Commands to run after transfer. See CURLOPT_POSTQUOTE(3) -+Proxy CA cert bundle. See CURLOPT_PROXY_CAINFO(3) - --## CURLOPT_PREQUOTE -+## CURLOPT_PROXY_CAINFO_BLOB - --Commands to run just before transfer. See CURLOPT_PREQUOTE(3) -+Proxy CA cert bundle memory buffer. See CURLOPT_PROXY_CAINFO_BLOB(3) - --## CURLOPT_APPEND -+## CURLOPT_PROXY_CAPATH - --Append to remote file. See CURLOPT_APPEND(3) -+Path to proxy CA cert bundle. See CURLOPT_PROXY_CAPATH(3) - --## CURLOPT_FTP_USE_EPRT -+## CURLOPT_PROXY_CRLFILE - --Use EPRT. See CURLOPT_FTP_USE_EPRT(3) -+Proxy Certificate Revocation List. See CURLOPT_PROXY_CRLFILE(3) - --## CURLOPT_FTP_USE_EPSV -+## CURLOPT_PROXY_ISSUERCERT - --Use EPSV. See CURLOPT_FTP_USE_EPSV(3) -+Proxy issuer certificate. See CURLOPT_PROXY_ISSUERCERT(3) - --## CURLOPT_FTP_USE_PRET -+## CURLOPT_PROXY_ISSUERCERT_BLOB - --Use PRET. See CURLOPT_FTP_USE_PRET(3) -+Proxy issuer certificate memory buffer. See CURLOPT_PROXY_ISSUERCERT_BLOB(3) - --## CURLOPT_FTP_CREATE_MISSING_DIRS -+## CURLOPT_PROXY_KEYPASSWD - --Create missing directories on the remote server. See CURLOPT_FTP_CREATE_MISSING_DIRS(3) -+Proxy client key password. See CURLOPT_PROXY_KEYPASSWD(3) - --## CURLOPT_SERVER_RESPONSE_TIMEOUT -+## CURLOPT_PROXY_PINNEDPUBLICKEY - --Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3) -+Set the proxy's pinned SSL public key. See -+CURLOPT_PROXY_PINNEDPUBLICKEY(3) - --## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS -+## CURLOPT_PROXY_SERVICE_NAME - --Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) -+Proxy authentication service name. CURLOPT_PROXY_SERVICE_NAME(3) - --## CURLOPT_FTP_ALTERNATIVE_TO_USER -+## CURLOPT_PROXY_SSLCERT - --Alternative to USER. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3) -+Proxy client cert. See CURLOPT_PROXY_SSLCERT(3) - --## CURLOPT_FTP_SKIP_PASV_IP -+## CURLOPT_PROXY_SSLCERTTYPE - --Ignore the IP address in the PASV response. See CURLOPT_FTP_SKIP_PASV_IP(3) -+Proxy client cert type. See CURLOPT_PROXY_SSLCERTTYPE(3) - --## CURLOPT_FTPSSLAUTH -+## CURLOPT_PROXY_SSLCERT_BLOB - --Control how to do TLS. See CURLOPT_FTPSSLAUTH(3) -+Proxy client cert memory buffer. See CURLOPT_PROXY_SSLCERT_BLOB(3) - --## CURLOPT_FTP_SSL_CCC -+## CURLOPT_PROXY_SSLKEY - --Back to non-TLS again after authentication. See CURLOPT_FTP_SSL_CCC(3) -+Proxy client key. See CURLOPT_PROXY_SSLKEY(3) - --## CURLOPT_FTP_ACCOUNT -+## CURLOPT_PROXY_SSLKEYTYPE - --Send ACCT command. See CURLOPT_FTP_ACCOUNT(3) -+Proxy client key type. See CURLOPT_PROXY_SSLKEYTYPE(3) - --## CURLOPT_FTP_FILEMETHOD -+## CURLOPT_PROXY_SSLKEY_BLOB - --Specify how to reach files. See CURLOPT_FTP_FILEMETHOD(3) -+Proxy client key. See CURLOPT_PROXY_SSLKEY_BLOB(3) - --# RTSP OPTIONS -+## CURLOPT_PROXY_SSLVERSION - --## CURLOPT_RTSP_REQUEST -+Proxy SSL version to use. See CURLOPT_PROXY_SSLVERSION(3) - --RTSP request. See CURLOPT_RTSP_REQUEST(3) -+## CURLOPT_PROXY_SSL_CIPHER_LIST - --## CURLOPT_RTSP_SESSION_ID -+Proxy ciphers to use. See CURLOPT_PROXY_SSL_CIPHER_LIST(3) - --RTSP session-id. See CURLOPT_RTSP_SESSION_ID(3) -+## CURLOPT_PROXY_SSL_OPTIONS - --## CURLOPT_RTSP_STREAM_URI -+Control proxy SSL behavior. See CURLOPT_PROXY_SSL_OPTIONS(3) - --RTSP stream URI. See CURLOPT_RTSP_STREAM_URI(3) -+## CURLOPT_PROXY_SSL_VERIFYHOST - --## CURLOPT_RTSP_TRANSPORT -+Verify the hostname in the proxy SSL certificate. See -+CURLOPT_PROXY_SSL_VERIFYHOST(3) - --RTSP Transport: header. See CURLOPT_RTSP_TRANSPORT(3) -+## CURLOPT_PROXY_SSL_VERIFYPEER - --## CURLOPT_RTSP_CLIENT_CSEQ -+Verify the proxy SSL certificate. See CURLOPT_PROXY_SSL_VERIFYPEER(3) - --Client CSEQ number. See CURLOPT_RTSP_CLIENT_CSEQ(3) -+## CURLOPT_PROXY_TLS13_CIPHERS - --## CURLOPT_RTSP_SERVER_CSEQ -+Proxy TLS 1.3 cipher suites to use. See CURLOPT_PROXY_TLS13_CIPHERS(3) - --CSEQ number for RTSP Server-\>Client request. See CURLOPT_RTSP_SERVER_CSEQ(3) -+## CURLOPT_PROXY_TLSAUTH_PASSWORD - --## CURLOPT_AWS_SIGV4 -+Proxy TLS authentication password. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3) - --AWS HTTP V4 Signature. See CURLOPT_AWS_SIGV4(3) -+## CURLOPT_PROXY_TLSAUTH_TYPE - --# PROTOCOL OPTIONS -+Proxy TLS authentication methods. See CURLOPT_PROXY_TLSAUTH_TYPE(3) - --## CURLOPT_TRANSFERTEXT -+## CURLOPT_PROXY_TLSAUTH_USERNAME - --Use text transfer. See CURLOPT_TRANSFERTEXT(3) -+Proxy TLS authentication username. See CURLOPT_PROXY_TLSAUTH_USERNAME(3) - - ## CURLOPT_PROXY_TRANSFER_MODE - - Add transfer mode to URL over proxy. See CURLOPT_PROXY_TRANSFER_MODE(3) - --## CURLOPT_CRLF -+## CURLOPT_PUT - --Convert newlines. See CURLOPT_CRLF(3) -+**Deprecated option** Issue an HTTP PUT request. See CURLOPT_PUT(3) - --## CURLOPT_RANGE -+## CURLOPT_QUICK_EXIT - --Range requests. See CURLOPT_RANGE(3) -+To be set by toplevel tools like "curl" to skip lengthy cleanups when they are -+about to call exit() anyway. See CURLOPT_QUICK_EXIT(3) - --## CURLOPT_RESUME_FROM -+## CURLOPT_QUOTE - --Resume a transfer. See CURLOPT_RESUME_FROM(3) -+Commands to run before transfer. See CURLOPT_QUOTE(3) - --## CURLOPT_RESUME_FROM_LARGE -+## CURLOPT_RANDOM_FILE - --Resume a transfer. See CURLOPT_RESUME_FROM_LARGE(3) -+**OBSOLETE** Provide source for entropy random data. -+See CURLOPT_RANDOM_FILE(3) - --## CURLOPT_CURLU -+## CURLOPT_RANGE - --Set URL to work on with a URL handle. See CURLOPT_CURLU(3) -+Range requests. See CURLOPT_RANGE(3) - --## CURLOPT_CUSTOMREQUEST -+## CURLOPT_READDATA - --Custom request/method. See CURLOPT_CUSTOMREQUEST(3) -+Data pointer to pass to the read callback. See CURLOPT_READDATA(3) - --## CURLOPT_FILETIME -+## CURLOPT_READFUNCTION - --Request file modification date and time. See CURLOPT_FILETIME(3) -+Callback for reading data. See CURLOPT_READFUNCTION(3) - --## CURLOPT_DIRLISTONLY -+## CURLOPT_REDIR_PROTOCOLS - --List only. See CURLOPT_DIRLISTONLY(3) -+**Deprecated option** Protocols to allow redirects to. See -+CURLOPT_REDIR_PROTOCOLS(3) - --## CURLOPT_NOBODY -+## CURLOPT_REDIR_PROTOCOLS_STR - --Do not get the body contents. See CURLOPT_NOBODY(3) -+Protocols to allow redirects to. See CURLOPT_REDIR_PROTOCOLS_STR(3) - --## CURLOPT_INFILESIZE -+## CURLOPT_REFERER - --Size of file to send. CURLOPT_INFILESIZE(3) -+Referer: header. See CURLOPT_REFERER(3) - --## CURLOPT_INFILESIZE_LARGE -+## CURLOPT_REQUEST_TARGET - --Size of file to send. CURLOPT_INFILESIZE_LARGE(3) -+Set the request target. CURLOPT_REQUEST_TARGET(3) - --## CURLOPT_UPLOAD -+## CURLOPT_RESOLVE - --Upload data. See CURLOPT_UPLOAD(3) -+Provide fixed/fake name resolves. See CURLOPT_RESOLVE(3) - --## CURLOPT_UPLOAD_BUFFERSIZE -+## CURLOPT_RESOLVER_START_DATA - --Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3) -+Data pointer to pass to resolver start callback. See -+CURLOPT_RESOLVER_START_DATA(3) - --## CURLOPT_MIMEPOST -+## CURLOPT_RESOLVER_START_FUNCTION - --Post/send MIME data. See CURLOPT_MIMEPOST(3) -+Callback to be called before a new resolve request is started. See -+CURLOPT_RESOLVER_START_FUNCTION(3) - --## CURLOPT_MIME_OPTIONS -+## CURLOPT_RESUME_FROM - --Set MIME option flags. See CURLOPT_MIME_OPTIONS(3) -+Resume a transfer. See CURLOPT_RESUME_FROM(3) - --## CURLOPT_MAXFILESIZE -+## CURLOPT_RESUME_FROM_LARGE - --Maximum file size to get. See CURLOPT_MAXFILESIZE(3) -+Resume a transfer. See CURLOPT_RESUME_FROM_LARGE(3) - --## CURLOPT_MAXFILESIZE_LARGE -+## CURLOPT_RTSP_CLIENT_CSEQ - --Maximum file size to get. See CURLOPT_MAXFILESIZE_LARGE(3) -+Client CSEQ number. See CURLOPT_RTSP_CLIENT_CSEQ(3) - --## CURLOPT_TIMECONDITION -+## CURLOPT_RTSP_REQUEST - --Make a time conditional request. See CURLOPT_TIMECONDITION(3) -+RTSP request. See CURLOPT_RTSP_REQUEST(3) - --## CURLOPT_TIMEVALUE -+## CURLOPT_RTSP_SERVER_CSEQ - --Time value for the time conditional request. See CURLOPT_TIMEVALUE(3) -+CSEQ number for RTSP Server-\>Client request. See CURLOPT_RTSP_SERVER_CSEQ(3) - --## CURLOPT_TIMEVALUE_LARGE -+## CURLOPT_RTSP_SESSION_ID - --Time value for the time conditional request. See CURLOPT_TIMEVALUE_LARGE(3) -+RTSP session-id. See CURLOPT_RTSP_SESSION_ID(3) - --# CONNECTION OPTIONS -+## CURLOPT_RTSP_STREAM_URI - --## CURLOPT_TIMEOUT -+RTSP stream URI. See CURLOPT_RTSP_STREAM_URI(3) - --Timeout for the entire request. See CURLOPT_TIMEOUT(3) -+## CURLOPT_RTSP_TRANSPORT - --## CURLOPT_TIMEOUT_MS -+RTSP Transport: header. See CURLOPT_RTSP_TRANSPORT(3) - --Millisecond timeout for the entire request. See CURLOPT_TIMEOUT_MS(3) -+## CURLOPT_SASL_AUTHZID - --## CURLOPT_LOW_SPEED_LIMIT -+SASL authorization identity (identity to act as). See CURLOPT_SASL_AUTHZID(3) - --Low speed limit to abort transfer. See CURLOPT_LOW_SPEED_LIMIT(3) -+## CURLOPT_SASL_IR - --## CURLOPT_LOW_SPEED_TIME -+Enable SASL initial response. See CURLOPT_SASL_IR(3) - --Time to be below the speed to trigger low speed abort. See CURLOPT_LOW_SPEED_TIME(3) -+## CURLOPT_SEEKDATA - --## CURLOPT_MAX_SEND_SPEED_LARGE -+Data pointer to pass to the seek callback. See CURLOPT_SEEKDATA(3) - --Cap the upload speed to this. See CURLOPT_MAX_SEND_SPEED_LARGE(3) -+## CURLOPT_SEEKFUNCTION - --## CURLOPT_MAX_RECV_SPEED_LARGE -+Callback for seek operations. See CURLOPT_SEEKFUNCTION(3) - --Cap the download speed to this. See CURLOPT_MAX_RECV_SPEED_LARGE(3) -+## CURLOPT_SERVER_RESPONSE_TIMEOUT - --## CURLOPT_MAXCONNECTS -+Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3) - --Maximum number of connections in the connection pool. See CURLOPT_MAXCONNECTS(3) -+## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS - --## CURLOPT_FRESH_CONNECT -+Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3) - --Use a new connection. CURLOPT_FRESH_CONNECT(3) -+## CURLOPT_SERVICE_NAME - --## CURLOPT_FORBID_REUSE -+Authentication service name. CURLOPT_SERVICE_NAME(3) - --Prevent subsequent connections from reusing this. See CURLOPT_FORBID_REUSE(3) -+## CURLOPT_SHARE - --## CURLOPT_MAXAGE_CONN -+Share object to use. See CURLOPT_SHARE(3) - --Limit the age (idle time) of connections for reuse. See CURLOPT_MAXAGE_CONN(3) -+## CURLOPT_SOCKOPTDATA - --## CURLOPT_MAXLIFETIME_CONN -+Data pointer to pass to the sockopt callback. See CURLOPT_SOCKOPTDATA(3) - --Limit the age (since creation) of connections for reuse. See --CURLOPT_MAXLIFETIME_CONN(3) -+## CURLOPT_SOCKOPTFUNCTION - --## CURLOPT_CONNECTTIMEOUT -+Callback for sockopt operations. See CURLOPT_SOCKOPTFUNCTION(3) - --Timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT(3) -+## CURLOPT_SOCKS5_AUTH - --## CURLOPT_CONNECTTIMEOUT_MS -+Socks5 authentication methods. See CURLOPT_SOCKS5_AUTH(3) - --Millisecond timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT_MS(3) -+## CURLOPT_SOCKS5_GSSAPI_NEC - --## CURLOPT_IPRESOLVE -+Socks5 GSSAPI NEC mode. See CURLOPT_SOCKS5_GSSAPI_NEC(3) - --IP version to use. See CURLOPT_IPRESOLVE(3) -+## CURLOPT_SOCKS5_GSSAPI_SERVICE - --## CURLOPT_CONNECT_ONLY -+**Deprecated option** Socks5 GSSAPI service name. -+See CURLOPT_SOCKS5_GSSAPI_SERVICE(3) - --Only connect, nothing else. See CURLOPT_CONNECT_ONLY(3) -+## CURLOPT_SSH_AUTH_TYPES - --## CURLOPT_USE_SSL -+SSH authentication types. See CURLOPT_SSH_AUTH_TYPES(3) - --Use TLS/SSL. See CURLOPT_USE_SSL(3) -+## CURLOPT_SSH_COMPRESSION - --## CURLOPT_RESOLVE -+Enable SSH compression. See CURLOPT_SSH_COMPRESSION(3) - --Provide fixed/fake name resolves. See CURLOPT_RESOLVE(3) -+## CURLOPT_SSH_HOSTKEYDATA - --## CURLOPT_DNS_INTERFACE -+Custom pointer to pass to ssh host key callback. See CURLOPT_SSH_HOSTKEYDATA(3) - --Bind name resolves to this interface. See CURLOPT_DNS_INTERFACE(3) -+## CURLOPT_SSH_HOSTKEYFUNCTION - --## CURLOPT_DNS_LOCAL_IP4 -+Callback for checking host key handling. See CURLOPT_SSH_HOSTKEYFUNCTION(3) - --Bind name resolves to this IP4 address. See CURLOPT_DNS_LOCAL_IP4(3) -+## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 - --## CURLOPT_DNS_LOCAL_IP6 -+MD5 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3) - --Bind name resolves to this IP6 address. See CURLOPT_DNS_LOCAL_IP6(3) -+## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 - --## CURLOPT_DNS_SERVERS -+SHA256 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3) - --Preferred DNS servers. See CURLOPT_DNS_SERVERS(3) -+## CURLOPT_SSH_KEYDATA - --## CURLOPT_DNS_SHUFFLE_ADDRESSES -+Custom pointer to pass to ssh key callback. See CURLOPT_SSH_KEYDATA(3) - --Shuffle addresses before use. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3) -+## CURLOPT_SSH_KEYFUNCTION - --## CURLOPT_ACCEPTTIMEOUT_MS -+Callback for known hosts handling. See CURLOPT_SSH_KEYFUNCTION(3) - --Timeout for waiting for the server's connect back to be accepted. See --CURLOPT_ACCEPTTIMEOUT_MS(3) -+## CURLOPT_SSH_KNOWNHOSTS - --## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS -+Filename with known hosts. See CURLOPT_SSH_KNOWNHOSTS(3) - --Timeout for happy eyeballs. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3) -+## CURLOPT_SSH_PRIVATE_KEYFILE - --## CURLOPT_UPKEEP_INTERVAL_MS -+Filename of the private key. See CURLOPT_SSH_PRIVATE_KEYFILE(3) - --Sets the interval at which connection upkeep are performed. See --CURLOPT_UPKEEP_INTERVAL_MS(3) -+## CURLOPT_SSH_PUBLIC_KEYFILE - --# SSL and SECURITY OPTIONS -+Filename of the public key. See CURLOPT_SSH_PUBLIC_KEYFILE(3) - - ## CURLOPT_SSLCERT - - Client cert. See CURLOPT_SSLCERT(3) - --## CURLOPT_SSLCERT_BLOB -- --Client cert memory buffer. See CURLOPT_SSLCERT_BLOB(3) -- --## CURLOPT_PROXY_SSLCERT -+## CURLOPT_SSLCERTTYPE - --Proxy client cert. See CURLOPT_PROXY_SSLCERT(3) -+Client cert type. See CURLOPT_SSLCERTTYPE(3) - --## CURLOPT_PROXY_SSLCERT_BLOB -+## CURLOPT_SSLCERT_BLOB - --Proxy client cert memory buffer. See CURLOPT_PROXY_SSLCERT_BLOB(3) -+Client cert memory buffer. See CURLOPT_SSLCERT_BLOB(3) - --## CURLOPT_SSLCERTTYPE -+## CURLOPT_SSLENGINE - --Client cert type. See CURLOPT_SSLCERTTYPE(3) -+Use identifier with SSL engine. See CURLOPT_SSLENGINE(3) - --## CURLOPT_PROXY_SSLCERTTYPE -+## CURLOPT_SSLENGINE_DEFAULT - --Proxy client cert type. See CURLOPT_PROXY_SSLCERTTYPE(3) -+Default SSL engine. See CURLOPT_SSLENGINE_DEFAULT(3) - - ## CURLOPT_SSLKEY - - Client key. See CURLOPT_SSLKEY(3) - --## CURLOPT_SSLKEY_BLOB -- --Client key memory buffer. See CURLOPT_SSLKEY_BLOB(3) -- --## CURLOPT_PROXY_SSLKEY -+## CURLOPT_SSLKEYTYPE - --Proxy client key. See CURLOPT_PROXY_SSLKEY(3) -+Client key type. See CURLOPT_SSLKEYTYPE(3) - --## CURLOPT_PROXY_SSLKEY_BLOB -+## CURLOPT_SSLKEY_BLOB - --Proxy client key. See CURLOPT_PROXY_SSLKEY_BLOB(3) -+Client key memory buffer. See CURLOPT_SSLKEY_BLOB(3) - --## CURLOPT_SSLKEYTYPE -+## CURLOPT_SSLVERSION - --Client key type. See CURLOPT_SSLKEYTYPE(3) -+SSL version to use. See CURLOPT_SSLVERSION(3) - --## CURLOPT_PROXY_SSLKEYTYPE -+## CURLOPT_SSL_CIPHER_LIST - --Proxy client key type. See CURLOPT_PROXY_SSLKEYTYPE(3) -+Ciphers to use. See CURLOPT_SSL_CIPHER_LIST(3) - --## CURLOPT_KEYPASSWD -+## CURLOPT_SSL_CTX_DATA - --Client key password. See CURLOPT_KEYPASSWD(3) -+Data pointer to pass to the SSL context callback. See CURLOPT_SSL_CTX_DATA(3) - --## CURLOPT_PROXY_KEYPASSWD -+## CURLOPT_SSL_CTX_FUNCTION - --Proxy client key password. See CURLOPT_PROXY_KEYPASSWD(3) -+Callback for SSL context logic. See CURLOPT_SSL_CTX_FUNCTION(3) - - ## CURLOPT_SSL_EC_CURVES - -@@ -1099,252 +1116,218 @@ Enable use of ALPN. See CURLOPT_SSL_ENABLE_ALPN(3) - - **OBSOLETE** Enable use of NPN. See CURLOPT_SSL_ENABLE_NPN(3) - --## CURLOPT_SSLENGINE -- --Use identifier with SSL engine. See CURLOPT_SSLENGINE(3) -- --## CURLOPT_SSLENGINE_DEFAULT -- --Default SSL engine. See CURLOPT_SSLENGINE_DEFAULT(3) -- - ## CURLOPT_SSL_FALSESTART - - Enable TLS False Start. See CURLOPT_SSL_FALSESTART(3) - --## CURLOPT_SSLVERSION -+## CURLOPT_SSL_OPTIONS - --SSL version to use. See CURLOPT_SSLVERSION(3) -+Control SSL behavior. See CURLOPT_SSL_OPTIONS(3) - --## CURLOPT_PROXY_SSLVERSION -+## CURLOPT_SSL_SESSIONID_CACHE - --Proxy SSL version to use. See CURLOPT_PROXY_SSLVERSION(3) -+Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3) - - ## CURLOPT_SSL_VERIFYHOST - - Verify the hostname in the SSL certificate. See CURLOPT_SSL_VERIFYHOST(3) - --## CURLOPT_DOH_SSL_VERIFYHOST -- --Verify the hostname in the DoH (DNS-over-HTTPS) SSL certificate. See --CURLOPT_DOH_SSL_VERIFYHOST(3) -- --## CURLOPT_PROXY_SSL_VERIFYHOST -- --Verify the hostname in the proxy SSL certificate. See --CURLOPT_PROXY_SSL_VERIFYHOST(3) -- - ## CURLOPT_SSL_VERIFYPEER - - Verify the SSL certificate. See CURLOPT_SSL_VERIFYPEER(3) - --## CURLOPT_DOH_SSL_VERIFYPEER -- --Verify the DoH (DNS-over-HTTPS) SSL certificate. See --CURLOPT_DOH_SSL_VERIFYPEER(3) -- --## CURLOPT_PROXY_SSL_VERIFYPEER -- --Verify the proxy SSL certificate. See CURLOPT_PROXY_SSL_VERIFYPEER(3) -- - ## CURLOPT_SSL_VERIFYSTATUS - - Verify the SSL certificate's status. See CURLOPT_SSL_VERIFYSTATUS(3) - --## CURLOPT_DOH_SSL_VERIFYSTATUS -- --Verify the DoH (DNS-over-HTTPS) SSL certificate's status. See --CURLOPT_DOH_SSL_VERIFYSTATUS(3) -- --## CURLOPT_CAINFO -- --CA cert bundle. See CURLOPT_CAINFO(3) -- --## CURLOPT_CAINFO_BLOB -+## CURLOPT_STDERR - --CA cert bundle memory buffer. See CURLOPT_CAINFO_BLOB(3) -+Redirect stderr to another stream. See CURLOPT_STDERR(3) - --## CURLOPT_PROXY_CAINFO -+## CURLOPT_STREAM_DEPENDS - --Proxy CA cert bundle. See CURLOPT_PROXY_CAINFO(3) -+This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3) - --## CURLOPT_PROXY_CAINFO_BLOB -+## CURLOPT_STREAM_DEPENDS_E - --Proxy CA cert bundle memory buffer. See CURLOPT_PROXY_CAINFO_BLOB(3) -+This HTTP/2 stream depends on another exclusively. See -+CURLOPT_STREAM_DEPENDS_E(3) - --## CURLOPT_ISSUERCERT -+## CURLOPT_STREAM_WEIGHT - --Issuer certificate. See CURLOPT_ISSUERCERT(3) -+Set this HTTP/2 stream's weight. See CURLOPT_STREAM_WEIGHT(3) - --## CURLOPT_ISSUERCERT_BLOB -+## CURLOPT_SUPPRESS_CONNECT_HEADERS - --Issuer certificate memory buffer. See CURLOPT_ISSUERCERT_BLOB(3) -+Suppress proxy CONNECT response headers from user callbacks. See -+CURLOPT_SUPPRESS_CONNECT_HEADERS(3) - --## CURLOPT_PROXY_ISSUERCERT -+## CURLOPT_TCP_FASTOPEN - --Proxy issuer certificate. See CURLOPT_PROXY_ISSUERCERT(3) -+Enable TCP Fast Open. See CURLOPT_TCP_FASTOPEN(3) - --## CURLOPT_PROXY_ISSUERCERT_BLOB -+## CURLOPT_TCP_KEEPALIVE - --Proxy issuer certificate memory buffer. See CURLOPT_PROXY_ISSUERCERT_BLOB(3) -+Enable TCP keep-alive. See CURLOPT_TCP_KEEPALIVE(3) - --## CURLOPT_CAPATH -+## CURLOPT_TCP_KEEPCNT - --Path to CA cert bundle. See CURLOPT_CAPATH(3) -+Maximum number of keep-alive probes. See CURLOPT_TCP_KEEPCNT(3) - --## CURLOPT_PROXY_CAPATH -+## CURLOPT_TCP_KEEPIDLE - --Path to proxy CA cert bundle. See CURLOPT_PROXY_CAPATH(3) -+Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3) - --## CURLOPT_CRLFILE -+## CURLOPT_TCP_KEEPINTVL - --Certificate Revocation List. See CURLOPT_CRLFILE(3) -+Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3) - --## CURLOPT_PROXY_CRLFILE -+## CURLOPT_TCP_NODELAY - --Proxy Certificate Revocation List. See CURLOPT_PROXY_CRLFILE(3) -+Disable the Nagle algorithm. See CURLOPT_TCP_NODELAY(3) - --## CURLOPT_CA_CACHE_TIMEOUT -+## CURLOPT_TELNETOPTIONS - --Timeout for CA cache. See CURLOPT_CA_CACHE_TIMEOUT(3) -+TELNET options. See CURLOPT_TELNETOPTIONS(3) - --## CURLOPT_CERTINFO -+## CURLOPT_TFTP_BLKSIZE - --Extract certificate info. See CURLOPT_CERTINFO(3) -+TFTP block size. See CURLOPT_TFTP_BLKSIZE(3) - --## CURLOPT_PINNEDPUBLICKEY -+## CURLOPT_TFTP_NO_OPTIONS - --Set pinned SSL public key . See CURLOPT_PINNEDPUBLICKEY(3) -+Do not send TFTP options requests. See CURLOPT_TFTP_NO_OPTIONS(3) - --## CURLOPT_PROXY_PINNEDPUBLICKEY -+## CURLOPT_TIMECONDITION - --Set the proxy's pinned SSL public key. See --CURLOPT_PROXY_PINNEDPUBLICKEY(3) -+Make a time conditional request. See CURLOPT_TIMECONDITION(3) - --## CURLOPT_RANDOM_FILE -+## CURLOPT_TIMEOUT - --**OBSOLETE** Provide source for entropy random data. --See CURLOPT_RANDOM_FILE(3) -+Timeout for the entire request. See CURLOPT_TIMEOUT(3) - --## CURLOPT_EGDSOCKET -+## CURLOPT_TIMEOUT_MS - --**OBSOLETE** Identify EGD socket for entropy. See CURLOPT_EGDSOCKET(3) -+Millisecond timeout for the entire request. See CURLOPT_TIMEOUT_MS(3) - --## CURLOPT_SSL_CIPHER_LIST -+## CURLOPT_TIMEVALUE - --Ciphers to use. See CURLOPT_SSL_CIPHER_LIST(3) -+Time value for the time conditional request. See CURLOPT_TIMEVALUE(3) - --## CURLOPT_PROXY_SSL_CIPHER_LIST -+## CURLOPT_TIMEVALUE_LARGE - --Proxy ciphers to use. See CURLOPT_PROXY_SSL_CIPHER_LIST(3) -+Time value for the time conditional request. See CURLOPT_TIMEVALUE_LARGE(3) - - ## CURLOPT_TLS13_CIPHERS - - TLS 1.3 cipher suites to use. See CURLOPT_TLS13_CIPHERS(3) - --## CURLOPT_PROXY_TLS13_CIPHERS -- --Proxy TLS 1.3 cipher suites to use. See CURLOPT_PROXY_TLS13_CIPHERS(3) -+## CURLOPT_TLSAUTH_PASSWORD - --## CURLOPT_SSL_SESSIONID_CACHE -+TLS authentication password. See CURLOPT_TLSAUTH_PASSWORD(3) - --Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3) -+## CURLOPT_TLSAUTH_TYPE - --## CURLOPT_SSL_OPTIONS -+TLS authentication methods. See CURLOPT_TLSAUTH_TYPE(3) - --Control SSL behavior. See CURLOPT_SSL_OPTIONS(3) -+## CURLOPT_TLSAUTH_USERNAME - --## CURLOPT_PROXY_SSL_OPTIONS -+TLS authentication username. See CURLOPT_TLSAUTH_USERNAME(3) - --Control proxy SSL behavior. See CURLOPT_PROXY_SSL_OPTIONS(3) -+## CURLOPT_TRAILERDATA - --## CURLOPT_KRBLEVEL -+Custom pointer passed to the trailing headers callback. See -+CURLOPT_TRAILERDATA(3) - --Kerberos security level. See CURLOPT_KRBLEVEL(3) -+## CURLOPT_TRAILERFUNCTION - --## CURLOPT_GSSAPI_DELEGATION -+Set callback for sending trailing headers. See -+CURLOPT_TRAILERFUNCTION(3) - --Disable GSS-API delegation. See CURLOPT_GSSAPI_DELEGATION(3) -+## CURLOPT_TRANSFERTEXT - --# SSH OPTIONS -+Use text transfer. See CURLOPT_TRANSFERTEXT(3) - --## CURLOPT_SSH_AUTH_TYPES -+## CURLOPT_TRANSFER_ENCODING - --SSH authentication types. See CURLOPT_SSH_AUTH_TYPES(3) -+Request Transfer-Encoding. See CURLOPT_TRANSFER_ENCODING(3) - --## CURLOPT_SSH_COMPRESSION -+## CURLOPT_UNIX_SOCKET_PATH - --Enable SSH compression. See CURLOPT_SSH_COMPRESSION(3) -+Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3) - --## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 -+## CURLOPT_UNRESTRICTED_AUTH - --MD5 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3) -+Do not restrict authentication to original host. CURLOPT_UNRESTRICTED_AUTH(3) - --## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 -+## CURLOPT_UPKEEP_INTERVAL_MS - --SHA256 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3) -+Sets the interval at which connection upkeep are performed. See -+CURLOPT_UPKEEP_INTERVAL_MS(3) - --## CURLOPT_SSH_PUBLIC_KEYFILE -+## CURLOPT_UPLOAD - --Filename of the public key. See CURLOPT_SSH_PUBLIC_KEYFILE(3) -+Upload data. See CURLOPT_UPLOAD(3) - --## CURLOPT_SSH_PRIVATE_KEYFILE -+## CURLOPT_UPLOAD_BUFFERSIZE - --Filename of the private key. See CURLOPT_SSH_PRIVATE_KEYFILE(3) -+Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3) - --## CURLOPT_SSH_KNOWNHOSTS -+## CURLOPT_URL - --Filename with known hosts. See CURLOPT_SSH_KNOWNHOSTS(3) -+URL to work on. See CURLOPT_URL(3) - --## CURLOPT_SSH_KEYFUNCTION -+## CURLOPT_USERAGENT - --Callback for known hosts handling. See CURLOPT_SSH_KEYFUNCTION(3) -+User-Agent: header. See CURLOPT_USERAGENT(3) - --## CURLOPT_SSH_KEYDATA -+## CURLOPT_USERNAME - --Custom pointer to pass to ssh key callback. See CURLOPT_SSH_KEYDATA(3) -+Username. See CURLOPT_USERNAME(3) - --## CURLOPT_SSH_HOSTKEYFUNCTION -+## CURLOPT_USERPWD - --Callback for checking host key handling. See CURLOPT_SSH_HOSTKEYFUNCTION(3) -+Username and password. See CURLOPT_USERPWD(3) - --## CURLOPT_SSH_HOSTKEYDATA -+## CURLOPT_USE_SSL - --Custom pointer to pass to ssh host key callback. See CURLOPT_SSH_HOSTKEYDATA(3) -+Use TLS/SSL. See CURLOPT_USE_SSL(3) - --# WEBSOCKET -+## CURLOPT_VERBOSE - --## CURLOPT_WS_OPTIONS -+Display verbose information. See CURLOPT_VERBOSE(3) - --Set WebSocket options. See CURLOPT_WS_OPTIONS(3) -+## CURLOPT_WILDCARDMATCH - --# OTHER OPTIONS -+Transfer multiple files according to a filename pattern. See -+CURLOPT_WILDCARDMATCH(3) - --## CURLOPT_PRIVATE -+## CURLOPT_WRITEDATA - --Private pointer to store. See CURLOPT_PRIVATE(3) -+Data pointer to pass to the write callback. See CURLOPT_WRITEDATA(3) - --## CURLOPT_SHARE -+## CURLOPT_WRITEFUNCTION - --Share object to use. See CURLOPT_SHARE(3) -+Callback for writing data. See CURLOPT_WRITEFUNCTION(3) - --## CURLOPT_NEW_FILE_PERMS -+## CURLOPT_WS_OPTIONS - --Mode for creating new remote files. See CURLOPT_NEW_FILE_PERMS(3) -+Set WebSocket options. See CURLOPT_WS_OPTIONS(3) - --## CURLOPT_NEW_DIRECTORY_PERMS -+## CURLOPT_XFERINFODATA - --Mode for creating new remote directories. See CURLOPT_NEW_DIRECTORY_PERMS(3) -+Data pointer to pass to the progress meter callback. See -+CURLOPT_XFERINFODATA(3) - --## CURLOPT_QUICK_EXIT -+## CURLOPT_XFERINFOFUNCTION - --To be set by toplevel tools like "curl" to skip lengthy cleanups when they are --about to call exit() anyway. See CURLOPT_QUICK_EXIT(3) -+Callback for progress meter. See CURLOPT_XFERINFOFUNCTION(3) - --# TELNET OPTIONS -+## CURLOPT_XOAUTH2_BEARER - --## CURLOPT_TELNETOPTIONS -+OAuth2 bearer token. See CURLOPT_XOAUTH2_BEARER(3) - --TELNET options. See CURLOPT_TELNETOPTIONS(3) -+# %PROTOCOLS% - - # EXAMPLE - -@@ -1361,9 +1344,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_strerror.md b/docs/libcurl/curl_easy_strerror.md -index 0555fe783..37040a1c1 100644 ---- a/docs/libcurl/curl_easy_strerror.md -+++ b/docs/libcurl/curl_easy_strerror.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.12.0 - --- - - # NAME -@@ -33,6 +34,8 @@ CURLcode error code passed in the argument *errornum*. - Typically applications also appreciate CURLOPT_ERRORBUFFER(3) for more - specific error descriptions generated at runtime. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -52,9 +55,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.12.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_unescape.md b/docs/libcurl/curl_easy_unescape.md -index 00951d96e..2e78ad5d9 100644 ---- a/docs/libcurl/curl_easy_unescape.md -+++ b/docs/libcurl/curl_easy_unescape.md -@@ -6,14 +6,15 @@ Section: 3 - Source: libcurl - See-also: - - curl_easy_escape (3) -- - curl_free (3) -+ - curl_url_get (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME - --curl_easy_unescape - URL decodes the given string -+curl_easy_unescape - URL decode a string - - # SYNOPSIS - -@@ -46,6 +47,8 @@ TPF, but it was otherwise ignored. - - You must curl_free(3) the returned string when you are done with it. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,7 +59,7 @@ int main(void) - int decodelen; - char *decoded = curl_easy_unescape(curl, "%63%75%72%6c", 12, &decodelen); - if(decoded) { -- /* do not assume printf() works on the decoded data! */ -+ /* do not assume printf() works on the decoded data */ - printf("Decoded: "); - /* ... */ - curl_free(decoded); -@@ -66,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.4 and replaces the old curl_unescape(3) function. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_easy_upkeep.md b/docs/libcurl/curl_easy_upkeep.md -index eec4ed2f4..1b2fef01a 100644 ---- a/docs/libcurl/curl_easy_upkeep.md -+++ b/docs/libcurl/curl_easy_upkeep.md -@@ -9,11 +9,12 @@ See-also: - - CURLOPT_TCP_KEEPIDLE (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME - --curl_easy_upkeep - Perform any connection upkeep checks. -+curl_easy_upkeep - keep existing connections alive - - # SYNOPSIS - -@@ -38,6 +39,12 @@ This function must be explicitly called in order to perform the upkeep work. - The connection upkeep interval is set with - CURLOPT_UPKEEP_INTERVAL_MS(3). - -+If you call this function on an easy handle that uses a shared connection cache -+then upkeep is performed on the connections in that cache, even if those -+connections were never used by the easy handle. (Added in 8.10.0) -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,9 +75,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_escape.md b/docs/libcurl/curl_escape.md -index d15a4debc..c24d1890d 100644 ---- a/docs/libcurl/curl_escape.md -+++ b/docs/libcurl/curl_escape.md -@@ -9,11 +9,12 @@ See-also: - - curl_unescape (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_escape - URL encodes the given string -+curl_escape - URL encode a string - - # SYNOPSIS - -@@ -25,7 +26,7 @@ char *curl_escape(const char *string, int length); - - # DESCRIPTION - --Obsolete function. Use curl_easy_escape(3) instead! -+Obsolete function. Use curl_easy_escape(3) instead. - - This function converts the given input **string** to a URL encoded string - and return that as a new allocated string. All input characters that are not -@@ -37,6 +38,8 @@ on **string** to find out the size. - - You must curl_free(3) the returned string when you are done with it. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,11 +53,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Since 7.15.4, curl_easy_escape(3) should be used. This function might be - removed in a future release. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - A pointer to a null-terminated string or NULL if it failed. -diff --git a/docs/libcurl/curl_formadd.md b/docs/libcurl/curl_formadd.md -index 0aefb26ee..b0f82f08c 100644 ---- a/docs/libcurl/curl_formadd.md -+++ b/docs/libcurl/curl_formadd.md -@@ -10,6 +10,7 @@ See-also: - - curl_mime_init (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -104,7 +105,7 @@ you must make sure strlen() on the data pointer returns zero. - - ## CURLFORM_CONTENTSLENGTH - --(This option is deprecated. Use *CURLFORM_CONTENTLEN* instead!) -+(This option is deprecated. Use *CURLFORM_CONTENTLEN* instead.) - - followed by a long giving the length of the contents. Note that for - *CURLFORM_STREAM* contents, this option is mandatory. -@@ -202,6 +203,8 @@ for the curl handle. - - See example below. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -299,7 +302,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Deprecated in 7.56.0. Before this release, field names were allowed to contain - zero-valued bytes. The pseudo-filename "-" to read stdin is discouraged -@@ -308,6 +311,8 @@ effective data size can then not be automatically determined, resulting in a - chunked encoding transfer. Backslashes and double quotes in field and - filenames are now escaped before transmission. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - 0 means everything was OK, non-zero means an error occurred corresponding to a -diff --git a/docs/libcurl/curl_formfree.md b/docs/libcurl/curl_formfree.md -index 1e0db8417..d7b4e303d 100644 ---- a/docs/libcurl/curl_formfree.md -+++ b/docs/libcurl/curl_formfree.md -@@ -10,6 +10,7 @@ See-also: - - curl_mime_init (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -26,7 +27,7 @@ void curl_formfree(struct curl_httppost *form); - - # DESCRIPTION - --This function is deprecated. Do not use. See curl_mime_init(3) instead! -+This function is deprecated. Do not use. See curl_mime_init(3) instead. - - curl_formfree() is used to clean up data previously built/appended with - curl_formadd(3). This must be called when the data has been used, which -@@ -42,6 +43,8 @@ curl_formadd(3) and may be NULL. - Passing in a NULL pointer in *form* makes this function return immediately - with no action. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,10 +72,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Deprecated in 7.56.0. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - None -diff --git a/docs/libcurl/curl_formget.md b/docs/libcurl/curl_formget.md -index 2ec8d119c..ad3efb9d4 100644 ---- a/docs/libcurl/curl_formget.md -+++ b/docs/libcurl/curl_formget.md -@@ -9,11 +9,12 @@ See-also: - - curl_mime_init (3) - Protocol: - - HTTP -+Added-in: 7.15.5 - --- - - # NAME - --curl_formget - serialize a previously built multipart form POST chain -+curl_formget - serialize a multipart form POST chain - - # SYNOPSIS - -@@ -26,9 +27,11 @@ int curl_formget(struct curl_httppost * form, void *userp, - - # DESCRIPTION - -+The form API (including this function) is deprecated since libcurl 7.56.0. -+ - curl_formget() serializes data previously built with curl_formadd(3). It --accepts a void pointer as second argument named *userp* which is passed as --the first argument to the curl_formget_callback function. -+accepts a void pointer as second argument named *userp* which is passed as the -+first argument to the curl_formget_callback function. - - ~~~c - typedef size_t (*curl_formget_callback)(void *userp, const char *buf, -@@ -40,9 +43,10 @@ character buffer passed to the callback must not be freed. The callback should - return the buffer length passed to it on success. - - If the **CURLFORM_STREAM** option is used in the formpost, it prevents --curl_formget(3) from working until you have performed the actual HTTP --request. This, because first then does libcurl known which actual read --callback to use! -+curl_formget(3) from working until you have performed the actual HTTP request. -+This, because first then does libcurl known which actual read callback to use. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -64,10 +68,7 @@ size_t print_httppost(struct curl_httppost *post) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.15.5. The form API is deprecated in --libcurl 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_free.md b/docs/libcurl/curl_free.md -index a758adf59..c10ca2803 100644 ---- a/docs/libcurl/curl_free.md -+++ b/docs/libcurl/curl_free.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_unescape (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -32,6 +33,8 @@ differences in memory management between your application and libcurl. - Passing in a NULL pointer in *ptr* makes this function return immediately - with no action. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -39,15 +42,13 @@ int main(void) - { - char *width = curl_getenv("COLUMNS"); - if(width) { -- /* it was set! */ -+ /* it was set */ - curl_free(width); - } - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_getdate.md b/docs/libcurl/curl_getdate.md -index 4a3849d69..00b4f9b73 100644 ---- a/docs/libcurl/curl_getdate.md -+++ b/docs/libcurl/curl_getdate.md -@@ -11,11 +11,12 @@ See-also: - - curl_easy_unescape (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_getdate - Convert a date string to number of seconds -+curl_getdate - convert date string to number of seconds - - # SYNOPSIS - -@@ -47,6 +48,9 @@ Can be specified several ways. Month names can only be three-letter English - abbreviations, numbers can be zero-prefixed and the year may use 2 or 4 - digits. Examples: 06 Nov 1994, 06-Nov-94 and Nov-94 6. - -+If the year appears to be below 100 (two-digit), any year after 70 is assumed -+to be 1900 + the given year. All others are 2000 + the given year. -+ - ## time of the day items - - This string specifies the time on a given day. You must specify it with 6 -@@ -62,7 +66,7 @@ UTC. Supported formats include: -1200, MST, +0100. - ## day of the week items - - Specifies a day of the week. Days of the week may be spelled out in full --(using English): `Sunday', `Monday', etc or they may be abbreviated to their -+(using English): 'Sunday', 'Monday', etc or they may be abbreviated to their - first three letters. This is usually not info that adds anything. - - ## pure numbers -@@ -71,6 +75,8 @@ If a decimal number of the form YYYYMMDD appears, then YYYY is read as the - year, MM as the month number and DD as the day of the month, for the specified - calendar date. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -110,21 +116,19 @@ RFC 1036) and ANSI C's *asctime()* format. - - These formats are the only ones RFC 7231 says HTTP applications may use. - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - - This function returns -1 when it fails to parse the date string. Otherwise it - returns the number of seconds as described. - --On systems with a signed 32 bit time_t: if the year is larger than 2037 or -+On systems with a signed 32-bit time_t: if the year is larger than 2037 or - less than 1903, this function returns -1. - --On systems with an unsigned 32 bit time_t: if the year is larger than 2106 or -+On systems with an unsigned 32-bit time_t: if the year is larger than 2106 or - less than 1970, this function returns -1. - --On systems with 64 bit time_t: if the year is less than 1583, this function -+On systems with 64-bit time_t: if the year is less than 1583, this function - returns -1. (The Gregorian calendar was first introduced 1582 so no "real" - dates in this way of doing dates existed before then.) -diff --git a/docs/libcurl/curl_getenv.md b/docs/libcurl/curl_getenv.md -index 0092c676b..2cfb58148 100644 ---- a/docs/libcurl/curl_getenv.md -+++ b/docs/libcurl/curl_getenv.md -@@ -8,6 +8,7 @@ See-also: - - getenv (3C) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -26,10 +27,12 @@ char *curl_getenv(const char *name); - - curl_getenv() is a portable wrapper for the getenv() function, meant to - emulate its behavior and provide an identical interface for all operating --systems libcurl builds on (including win32). -+systems libcurl builds on (including Windows). - - You must curl_free(3) the returned string when you are done with it. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -37,15 +40,13 @@ int main(void) - { - char *width = curl_getenv("COLUMNS"); - if(width) { -- /* it was set! */ -+ /* it was set */ - curl_free(width); - } - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -@@ -54,6 +55,6 @@ specified name. - - # NOTE - --Under unix operating systems, there is no point in returning an allocated -+Under Unix operating systems, there is no point in returning an allocated - memory, although other systems does not work properly if this is not done. The --unix implementation thus suffers slightly from the drawbacks of other systems. -+Unix implementation thus suffers slightly from the drawbacks of other systems. -diff --git a/docs/libcurl/curl_global_cleanup.md b/docs/libcurl/curl_global_cleanup.md -index 11adb2b55..60a761ed5 100644 ---- a/docs/libcurl/curl_global_cleanup.md -+++ b/docs/libcurl/curl_global_cleanup.md -@@ -10,6 +10,7 @@ See-also: - - libcurl-thread (3) - Protocol: - - All -+Added-in: 7.8 - --- - - # NAME -@@ -54,6 +55,13 @@ still running then your program may crash or other corruption may occur. We - recommend you do not run libcurl from any module that may be unloaded - dynamically. This behavior may be addressed in the future. - -+libcurl may not be able to fully clean up after multi-threaded OpenSSL -+depending on how OpenSSL was built and loaded as a library. It is possible in -+some rare circumstances a memory leak could occur unless you implement your own -+OpenSSL thread cleanup. Refer to libcurl-thread(3). -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +75,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.8 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_global_init.md b/docs/libcurl/curl_global_init.md -index e48a1f36f..198b6e9f3 100644 ---- a/docs/libcurl/curl_global_init.md -+++ b/docs/libcurl/curl_global_init.md -@@ -13,11 +13,12 @@ See-also: - - libcurl (3) - Protocol: - - All -+Added-in: 7.8 - --- - - # NAME - --curl_global_init - Global libcurl initialization -+curl_global_init - global libcurl initialization - - # SYNOPSIS - -@@ -44,16 +45,15 @@ In normal operation, you must specify CURL_GLOBAL_ALL. Do not use any other - value unless you are familiar with it and mean to control internal operations - of libcurl. - --This function is thread-safe since libcurl 7.84.0 if --curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set --(most platforms). -+This function is thread-safe on most platforms. Then curl_version_info(3) has -+the `threadsafe` feature set (added in 7.84.0). - --If this is not thread-safe, you must not call this function when any other --thread in the program (i.e. a thread sharing the same memory) is running. --This does not just mean no other thread that is using libcurl. Because --curl_global_init(3) calls functions of other libraries that are --similarly thread unsafe, it could conflict with any other thread that uses --these other libraries. -+If this is not thread-safe (the bit mentioned above is not set), you must not -+call this function when any other thread in the program (i.e. a thread sharing -+the same memory) is running. This does not just mean no other thread that is -+using libcurl. Because curl_global_init(3) calls functions of other libraries -+that are similarly thread unsafe, it could conflict with any other thread that -+uses these other libraries. - - If you are initializing libcurl from a Windows DLL you should not initialize - it from *DllMain* or a static initializer because Windows holds the loader -@@ -89,7 +89,7 @@ unexpected behaviors. - Initialize the Win32 socket libraries. - - The implication here is that if this bit is not set, the initialization of --winsock has to be done by the application or you risk getting undefined -+Winsock has to be done by the application or you risk getting undefined - behaviors. This option exists for when the initialization is handled outside - of libcurl so there is no need for libcurl to do it again. - -@@ -110,6 +110,8 @@ Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when - connecting or when waiting for data. Otherwise, curl waits until full timeout - elapses. (Added in 7.30.0) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -123,9 +125,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.8 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_global_init_mem.md b/docs/libcurl/curl_global_init_mem.md -index 229d4d606..4ac22fbeb 100644 ---- a/docs/libcurl/curl_global_init_mem.md -+++ b/docs/libcurl/curl_global_init_mem.md -@@ -9,11 +9,12 @@ See-also: - - curl_global_init (3) - Protocol: - - All -+Added-in: 7.12.0 - --- - - # NAME - --curl_global_init_mem - Global libcurl initialization with memory callbacks -+curl_global_init_mem - global libcurl initialization with memory callbacks - - # SYNOPSIS - -@@ -68,7 +69,9 @@ to that man page for documentation. - # CAUTION - - Manipulating these gives considerable powers to the application to severely --screw things up for libcurl. Take care! -+screw things up for libcurl. Take care. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -87,9 +90,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.12.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_global_sslset.md b/docs/libcurl/curl_global_sslset.md -index 1fdc2d320..42123d71c 100644 ---- a/docs/libcurl/curl_global_sslset.md -+++ b/docs/libcurl/curl_global_sslset.md -@@ -9,11 +9,12 @@ See-also: - - libcurl (3) - Protocol: - - All -+Added-in: 7.56.0 - --- - - # NAME - --curl_global_sslset - Select SSL backend to use with libcurl -+curl_global_sslset - select SSL backend to use - - # SYNOPSIS - -@@ -66,7 +67,7 @@ This does not just mean no other thread that is using libcurl. - # OpenSSL - - The name "OpenSSL" is used for all versions of OpenSSL and its associated --forks/flavors in this function. OpenSSL, BoringSSL, libressl, quictls and -+forks/flavors in this function. OpenSSL, BoringSSL, LibreSSL, quictls and - AmiSSL are all supported by libcurl, but in the eyes of - curl_global_sslset(3) they are all just "OpenSSL". They all mostly - provide the same API. -@@ -100,6 +101,8 @@ typedef enum { - } curl_sslbackend; - ~~~ - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -119,10 +122,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.56.0. Before this version, there was no --support for choosing SSL backends at runtime. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_global_trace.md b/docs/libcurl/curl_global_trace.md -index 8aae45784..bf722ae6f 100644 ---- a/docs/libcurl/curl_global_trace.md -+++ b/docs/libcurl/curl_global_trace.md -@@ -9,11 +9,12 @@ See-also: - - libcurl (3) - Protocol: - - All -+Added-in: 8.3 - --- - - # NAME - --curl_global_trace - Global libcurl logging configuration -+curl_global_trace - log configuration - - # SYNOPSIS - -@@ -25,35 +26,34 @@ CURLcode curl_global_trace(const char *config); - - # DESCRIPTION - --This function configures the logging behavior, allowing to make some --parts of curl more verbose or silent than others. -+This function configures the logging behavior to make some parts of curl more -+verbose or silent than others. - - This function may be called during the initialization phase of a program. It - does not have to be. It can be called several times even, possibly overwriting - settings of previous calls. - --Calling this function after transfers have been started is undefined. On --some platforms/architectures it might take effect, on others not. -+Calling this function after transfers have been started is undefined. On some -+platforms/architectures it might take effect, on others not. - --This function is thread-safe since libcurl 8.3.0 if --curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set --(most platforms). -+This function is thread-safe since libcurl 8.3.0 if curl_version_info(3) has -+the CURL_VERSION_THREADSAFE feature bit set (most platforms). - - If this is not thread-safe, you must not call this function when any other --thread in the program (i.e. a thread sharing the same memory) is running. --This does not just mean no other thread that is using libcurl. Because --curl_global_init(3) may call functions of other libraries that are --similarly thread unsafe, it could conflict with any other thread that uses --these other libraries. -+thread in the program (i.e. a thread sharing the same memory) is running. This -+does not just mean no other thread that is using libcurl. Because -+curl_global_init(3) may call functions of other libraries that are similarly -+thread unsafe, it could conflict with any other thread that uses these other -+libraries. - - If you are initializing libcurl from a Windows DLL you should not initialize - it from *DllMain* or a static initializer because Windows holds the loader - lock during that time and it could cause a deadlock. - --The *config* string is a list of comma-separated component names. Names --are case-insensitive and unknown names are ignored. The special name "all" --applies to all components. Names may be prefixed with '+' or '-' to enable --or disable detailed logging for a component. -+The *config* string is a list of comma-separated component names. Names are -+case-insensitive and unknown names are ignored. The special name "all" applies -+to all components. Names may be prefixed with '+' or '-' to enable or disable -+detailed logging for a component. - - The list of component names is not part of curl's public API. Names may be - added or disappear in future versions of libcurl. Since unknown names are -@@ -61,20 +61,24 @@ silently ignored, outdated log configurations does not cause errors when - upgrading libcurl. Given that, some names can be expected to be fairly stable - and are listed below for easy reference. - --Note that log configuration applies only to transfers where debug logging --is enabled. See CURLOPT_VERBOSE(3) or CURLOPT_DEBUGFUNCTION(3) --on how to control that. -+Note that log configuration applies only to transfers where debug logging is -+enabled. See CURLOPT_VERBOSE(3) or CURLOPT_DEBUGFUNCTION(3) on how to control -+that. - - # TRACE COMPONENTS - - ## `tcp` - --Tracing of TCP socket handling: connect, reads, writes. -+Tracing of TCP socket handling: connect, sends, receives. - - ## `ssl` - - Tracing of SSL/TLS operations, whichever SSL backend is used in your build. - -+## `ftp` -+ -+Tracing of FTP operations when this protocol is enabled in your build. -+ - ## `http/2` - - Details about HTTP/2 handling: frames, events, I/O, etc. -@@ -97,6 +101,45 @@ trace. - - Tracing of DNS-over-HTTP operations to resolve hostnames. - -+## `read` -+ -+Traces reading of upload data from the application in order to send it to the server. -+ -+## `smtp` -+ -+Tracing of SMTP operations when this protocol is enabled in your build. -+ -+## `write` -+ -+Traces writing of download data, received from the server, to the application. -+ -+## `ws` -+ -+Tracing of WebSocket operations when this protocol is enabled in your build. -+ -+# TRACE GROUPS -+ -+Besides the specific component names there are the following group names -+defined: -+ -+## `all` -+ -+## `network` -+ -+All components involved in bare network I/O, including the SSL layer. -+ -+All components that your libcurl is built with. -+ -+## `protocol` -+ -+All components involved in transfer protocols, such as 'ftp' and 'http/2'. -+ -+## `proxy` -+ -+All components involved in use of proxies. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -120,9 +163,7 @@ of an enabled component appears at the beginning in brackets. - ... - ~~~ - --# AVAILABILITY -- --Added in 8.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_addpart.md b/docs/libcurl/curl_mime_addpart.md -index 53aea78b8..9a21295d5 100644 ---- a/docs/libcurl/curl_mime_addpart.md -+++ b/docs/libcurl/curl_mime_addpart.md -@@ -19,6 +19,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -42,6 +43,8 @@ subsequently be populated using functions from the mime API. - *mime* is the handle of the mime structure in which the new part must be - appended. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_data.md b/docs/libcurl/curl_mime_data.md -index a7f0571a9..5db64a951 100644 ---- a/docs/libcurl/curl_mime_data.md -+++ b/docs/libcurl/curl_mime_data.md -@@ -13,6 +13,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -49,6 +50,8 @@ last call is retained. It is possible to unassign part's contents by setting - Setting large data is memory consuming: one might consider using - curl_mime_data_cb(3) in such a case. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_data_cb.md b/docs/libcurl/curl_mime_data_cb.md -index e63ae42f2..f85e23e96 100644 ---- a/docs/libcurl/curl_mime_data_cb.md -+++ b/docs/libcurl/curl_mime_data_cb.md -@@ -13,6 +13,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -97,6 +98,8 @@ the pointed item to be shared between the original and the copied handle. In - particular, special attention should be given to the *freefunc* procedure - code since it then gets called twice with the same argument. - -+# %PROTOCOLS% -+ - # EXAMPLE - - Sending a huge data string causes the same amount of memory to be allocated: -@@ -163,9 +166,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_encoder.md b/docs/libcurl/curl_mime_encoder.md -index 8bd6bbdf2..1479bd7ff 100644 ---- a/docs/libcurl/curl_mime_encoder.md -+++ b/docs/libcurl/curl_mime_encoder.md -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -70,6 +71,8 @@ Encoding should not be applied to multiparts, thus the use of this function on - a part with content set with curl_mime_subparts(3) is strongly - discouraged. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -95,9 +98,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_filedata.md b/docs/libcurl/curl_mime_filedata.md -index 3f4640911..079330ed9 100644 ---- a/docs/libcurl/curl_mime_filedata.md -+++ b/docs/libcurl/curl_mime_filedata.md -@@ -13,6 +13,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -55,6 +56,8 @@ part is transferred using chunks by HTTP but is rejected by IMAP. - Setting a part's contents multiple times is valid: only the value set by the - last call is retained. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -80,9 +83,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_filename.md b/docs/libcurl/curl_mime_filename.md -index d642a6683..cfaeada8e 100644 ---- a/docs/libcurl/curl_mime_filename.md -+++ b/docs/libcurl/curl_mime_filename.md -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -43,6 +44,8 @@ The remote filename string is copied into the part, thus the associated - storage may safely be released or reused after call. Setting a part's file - name multiple times is valid: only the value set by the last call is retained. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -74,9 +77,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_free.md b/docs/libcurl/curl_mime_free.md -index 92106c33b..851b1c521 100644 ---- a/docs/libcurl/curl_mime_free.md -+++ b/docs/libcurl/curl_mime_free.md -@@ -11,6 +11,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -42,6 +43,8 @@ curl_mime_init(3) and may be NULL. - Passing in a NULL pointer in *mime* makes this function return immediately - with no action. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_headers.md b/docs/libcurl/curl_mime_headers.md -index 77669ac59..996266112 100644 ---- a/docs/libcurl/curl_mime_headers.md -+++ b/docs/libcurl/curl_mime_headers.md -@@ -11,6 +11,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -42,6 +43,8 @@ freed explicitly. - Setting a part's custom headers list multiple times is valid: only the value - set by the last call is retained. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -73,9 +76,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_init.md b/docs/libcurl/curl_mime_init.md -index 6702021ad..7d1513dfb 100644 ---- a/docs/libcurl/curl_mime_init.md -+++ b/docs/libcurl/curl_mime_init.md -@@ -13,6 +13,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -41,6 +42,8 @@ reporting. Since 7.87.0, it does not need to be the final target handle. - Using a mime handle is the recommended way to post an HTTP form, format and - send a multi-part email with SMTP or upload such an email to an IMAP server. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_name.md b/docs/libcurl/curl_mime_name.md -index 7f0d308f4..862784431 100644 ---- a/docs/libcurl/curl_mime_name.md -+++ b/docs/libcurl/curl_mime_name.md -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -40,6 +41,8 @@ safely be released or reused after call. Setting a part's name multiple times - is valid: only the value set by the last call is retained. It is possible to - reset the name of a part by setting *name* to NULL. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_subparts.md b/docs/libcurl/curl_mime_subparts.md -index 9c57297af..8056a3350 100644 ---- a/docs/libcurl/curl_mime_subparts.md -+++ b/docs/libcurl/curl_mime_subparts.md -@@ -11,6 +11,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -41,6 +42,8 @@ Setting a part's contents multiple times is valid: only the value set by the - last call is retained. It is possible to unassign previous part's contents by - setting *subparts* to NULL. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mime_type.md b/docs/libcurl/curl_mime_type.md -index 59ac01950..76f3d710d 100644 ---- a/docs/libcurl/curl_mime_type.md -+++ b/docs/libcurl/curl_mime_type.md -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.56.0 - --- - - # NAME -@@ -53,6 +54,8 @@ extension, or application/octet-stream by default. - - - text/plain in other cases. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -81,9 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_mprintf.md b/docs/libcurl/curl_mprintf.md -index b98bcec21..8f1daa8c2 100644 ---- a/docs/libcurl/curl_mprintf.md -+++ b/docs/libcurl/curl_mprintf.md -@@ -11,11 +11,12 @@ See-also: - - vprintf (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf -+curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf, - curl_mvaprintf, curl_mvfprintf, curl_mvprintf, curl_mvsnprintf, - curl_mvsprintf - formatted output conversion - -@@ -184,7 +185,7 @@ pointer to a long argument - - (ell-ell). A following integer conversion corresponds to a *long long* or - *unsigned long long* argument, or a following n conversion corresponds to --a pointer to a long long argument. -+a pointer to a *long long* argument. - - ## q - -@@ -263,6 +264,8 @@ by the corresponding argument. - - A '%' symbol is written. No argument is converted. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -275,10 +278,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --These functions might be removed from the public libcurl API in the future. Do --not use them in new programs or projects. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_add_handle.md b/docs/libcurl/curl_multi_add_handle.md -index 3f6120fc4..9082e9c48 100644 ---- a/docs/libcurl/curl_multi_add_handle.md -+++ b/docs/libcurl/curl_multi_add_handle.md -@@ -12,6 +12,7 @@ See-also: - - curl_multi_socket_action (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -63,6 +64,8 @@ first the easy handle and then the multi handle: - - 3 - curl_multi_cleanup(3) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -81,9 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_assign.md b/docs/libcurl/curl_multi_assign.md -index dd32b36b0..507291004 100644 ---- a/docs/libcurl/curl_multi_assign.md -+++ b/docs/libcurl/curl_multi_assign.md -@@ -9,6 +9,7 @@ See-also: - - curl_multi_socket_action (3) - Protocol: - - All -+Added-in: 7.15.5 - --- - - # NAME -@@ -47,6 +48,8 @@ functionality. - - It is acceptable to call this function from your multi callback functions. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -63,14 +66,6 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.5 -- --# RETURN VALUE -- --The standard CURLMcode for multi interface error codes. -- - # TYPICAL USAGE - - In a typical application you allocate a struct or at least use some kind of -@@ -78,6 +73,12 @@ semi-dynamic data for each socket that we must wait for action on when using - the curl_multi_socket_action(3) approach. - - When our socket-callback gets called by libcurl and we get to know about yet --another socket to wait for, we can use curl_multi_assign(3) to point out --the particular data so that when we get updates about this same socket again, --we do not have to find the struct associated with this socket by ourselves. -+another socket to wait for, we can use curl_multi_assign(3) to point out the -+particular data so that when we get updates about this same socket again, we -+do not have to find the struct associated with this socket by ourselves. -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+The standard CURLMcode for multi interface error codes. -diff --git a/docs/libcurl/curl_multi_cleanup.md b/docs/libcurl/curl_multi_cleanup.md -index e8e02a4b0..21661ea8a 100644 ---- a/docs/libcurl/curl_multi_cleanup.md -+++ b/docs/libcurl/curl_multi_cleanup.md -@@ -11,6 +11,7 @@ See-also: - - curl_multi_init (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -27,10 +28,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle); - - # DESCRIPTION - --Cleans up and removes a whole multi stack. It does not free or touch any --individual easy handles in any way - they still need to be closed --individually, using the usual curl_easy_cleanup(3) way. The order of --cleaning up should be: -+This function is the opposite of curl_multi_init(3). Cleans up and removes a -+whole multi stack. It does not free or touch any individual easy handles in -+any way - they still need to be closed individually, using the usual -+curl_easy_cleanup(3) way. The order of cleaning up should be: - - 1 - curl_multi_remove_handle(3) before any easy handles are cleaned up - -@@ -40,9 +41,17 @@ handle is no longer connected to the multi handle - 3 - curl_multi_cleanup(3) should be called when all easy handles are - removed - -+When this function is called, remaining entries in the connection pool held by -+the multi handle are shut down, which might trigger calls to the -+CURLMOPT_SOCKETFUNCTION(3) callback. -+ - Passing in a NULL pointer in *multi_handle* makes this function return - CURLM_BAD_HANDLE immediately with no other action. - -+Any use of the **multi_handle** after this function has been called and have -+returned, is illegal. -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +66,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_fdset.md b/docs/libcurl/curl_multi_fdset.md -index 1fe6e1f67..e1b869411 100644 ---- a/docs/libcurl/curl_multi_fdset.md -+++ b/docs/libcurl/curl_multi_fdset.md -@@ -10,14 +10,16 @@ See-also: - - curl_multi_perform (3) - - curl_multi_timeout (3) - - curl_multi_wait (3) -+ - curl_multi_waitfds (3) - - select (2) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME - --curl_multi_fdset - extracts file descriptor information from a multi handle -+curl_multi_fdset - extract file descriptor information from a multi handle - - # SYNOPSIS - -@@ -77,6 +79,8 @@ which can cause crashes, or worse. The effect of NOT storing it might possibly - save you from the crash, but makes your program NOT wait for sockets it should - wait for... - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -111,9 +115,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_get_handles.md b/docs/libcurl/curl_multi_get_handles.md -index a0b4bfb9c..f94436a88 100644 ---- a/docs/libcurl/curl_multi_get_handles.md -+++ b/docs/libcurl/curl_multi_get_handles.md -@@ -11,11 +11,12 @@ See-also: - - curl_multi_remove_handle (3) - Protocol: - - All -+Added-in: 8.4.0 - --- - - # NAME - --curl_multi_get_handles - returns all added easy handles -+curl_multi_get_handles - return all added easy handles - - # SYNOPSIS - -@@ -42,6 +43,8 @@ The order of the easy handles within the array is not guaranteed. - - The returned array must be freed with a call to curl_free(3) after use. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -70,9 +73,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 8.4.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_info_read.md b/docs/libcurl/curl_multi_info_read.md -index 0ba3ee352..3a8af88d0 100644 ---- a/docs/libcurl/curl_multi_info_read.md -+++ b/docs/libcurl/curl_multi_info_read.md -@@ -10,6 +10,7 @@ See-also: - - curl_multi_perform (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -66,6 +67,8 @@ that just completed. - - At this point, there are no other **msg** types defined. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -93,9 +96,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_init.md b/docs/libcurl/curl_multi_init.md -index 043198557..28c3d69c6 100644 ---- a/docs/libcurl/curl_multi_init.md -+++ b/docs/libcurl/curl_multi_init.md -@@ -12,6 +12,7 @@ See-also: - - curl_multi_get_handles (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -33,6 +34,12 @@ all the other multi-functions, sometimes referred to as a multi handle in some - places in the documentation. This init call MUST have a corresponding call to - curl_multi_cleanup(3) when the operation is complete. - -+By default, several caches are stored in and held by the multi handle: DNS -+cache, connection pool, TLS session ID cache and the TLS CA cert cache. All -+transfers using the same multi handle share these caches. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -49,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_perform.md b/docs/libcurl/curl_multi_perform.md -index eebed6e7d..c30ad2116 100644 ---- a/docs/libcurl/curl_multi_perform.md -+++ b/docs/libcurl/curl_multi_perform.md -@@ -14,11 +14,12 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME - --curl_multi_perform - reads/writes available data from easy handles -+curl_multi_perform - run all transfers until it would block - - # SYNOPSIS - -@@ -60,13 +61,15 @@ they cannot be continued. curl_multi_perform(3) should not be called - again on the same multi handle after an error has been returned, unless first - removing all the handles and adding new ones. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c - int main(void) - { - int still_running; -- CURL *multi = curl_multi_init(); -+ CURLM *multi = curl_multi_init(); - CURL *curl = curl_easy_init(); - if(curl) { - curl_multi_add_handle(multi, curl); -@@ -82,15 +85,13 @@ int main(void) - break; - } - -- /* if there are still transfers, loop! */ -+ /* if there are still transfers, loop */ - } while(still_running); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_poll.md b/docs/libcurl/curl_multi_poll.md -index 360e14d8e..c19661d0e 100644 ---- a/docs/libcurl/curl_multi_poll.md -+++ b/docs/libcurl/curl_multi_poll.md -@@ -11,11 +11,12 @@ See-also: - - curl_multi_wakeup (3) - Protocol: - - All -+Added-in: 7.66.0 - --- - - # NAME - --curl_multi_poll - polls on all easy handles in a multi handle -+curl_multi_poll - poll on all easy handles in a multi handle - - # SYNOPSIS - -@@ -86,14 +87,19 @@ priority read events such as out of band data. - Bit flag to curl_waitfd.events indicating the socket should poll on write - events such as the socket being clear to write without blocking. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -+extern void handle_fd(int); -+ - int main(void) - { - CURL *easy_handle; - CURLM *multi_handle; - int still_running = 0; -+ int myfd; /* this is our own file descriptor */ - - /* add the individual easy handle */ - curl_multi_add_handle(multi_handle, easy_handle); -@@ -105,8 +111,19 @@ int main(void) - mc = curl_multi_perform(multi_handle, &still_running); - - if(mc == CURLM_OK) { -- /* wait for activity or timeout */ -- mc = curl_multi_poll(multi_handle, NULL, 0, 1000, &numfds); -+ struct curl_waitfd myown; -+ myown.fd = myfd; -+ myown.events = CURL_WAIT_POLLIN; /* wait for input */ -+ myown.revents = 0; /* clear it */ -+ -+ /* wait for activity on curl's descriptors or on our own, -+ or timeout */ -+ mc = curl_multi_poll(multi_handle, &myown, 1, 1000, &numfds); -+ -+ if(myown.revents) { -+ /* did our descriptor receive an event? */ -+ handle_fd(myfd); -+ } - } - - if(mc != CURLM_OK) { -@@ -120,9 +137,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.66.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_remove_handle.md b/docs/libcurl/curl_multi_remove_handle.md -index b026466ac..ac43a592e 100644 ---- a/docs/libcurl/curl_multi_remove_handle.md -+++ b/docs/libcurl/curl_multi_remove_handle.md -@@ -10,6 +10,7 @@ See-also: - - curl_multi_init (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -46,6 +47,8 @@ libcurl keeps the connection alive in the connection pool associated with the - multi handle, ready to get reused for a future transfer using this multi - handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_setopt.md b/docs/libcurl/curl_multi_setopt.md -index 399060fc2..3f326be76 100644 ---- a/docs/libcurl/curl_multi_setopt.md -+++ b/docs/libcurl/curl_multi_setopt.md -@@ -11,6 +11,7 @@ See-also: - - curl_multi_socket (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -22,85 +23,88 @@ curl_multi_setopt - set options for a curl multi handle - ~~~c - #include - --CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option, parameter); -+CURLMcode curl_multi_setopt(CURLM *multi, CURLMoption option, parameter); - ~~~ - - # DESCRIPTION - --curl_multi_setopt(3) is used to tell a libcurl multi handle how to --behave. By using the appropriate options to curl_multi_setopt(3), you --can change libcurl's behavior when using that multi handle. All options are --set with the *option* followed by the *parameter*. That parameter can --be a **long**, a **function pointer**, an **object pointer** or a --**curl_off_t** type, depending on what the specific option expects. Read --this manual carefully as bad input values may cause libcurl to behave --badly. You can only set one option in each function call. -+curl_multi_setopt(3) is used to tell a libcurl multi handle how to behave. By -+using the appropriate options to curl_multi_setopt(3), you can change -+libcurl's behavior when using that multi handle. All options are set with the -+*option* followed by the *parameter*. That parameter can be a **long**, a -+**function pointer**, an **object pointer** or a **curl_off_t** type, -+depending on what the specific option expects. Read this manual carefully as -+bad input values may cause libcurl to behave badly. You can only set one -+option in each function call. - - # OPTIONS - - ## CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE - --See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3) -+**deprecated** See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3) - - ## CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE - --See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3) -+**deprecated** See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3) - --## CURLMOPT_MAX_HOST_CONNECTIONS -+## CURLMOPT_MAXCONNECTS - --See CURLMOPT_MAX_HOST_CONNECTIONS(3) -+Size of connection cache. See CURLMOPT_MAXCONNECTS(3) - --## CURLMOPT_MAX_PIPELINE_LENGTH -+## CURLMOPT_MAX_CONCURRENT_STREAMS - --See CURLMOPT_MAX_PIPELINE_LENGTH(3) -+Max concurrent streams for http2. See CURLMOPT_MAX_CONCURRENT_STREAMS(3) - --## CURLMOPT_MAX_TOTAL_CONNECTIONS -+## CURLMOPT_MAX_HOST_CONNECTIONS - --See CURLMOPT_MAX_TOTAL_CONNECTIONS(3) -+Max number of connections to a single host. See -+CURLMOPT_MAX_HOST_CONNECTIONS(3) - --## CURLMOPT_MAXCONNECTS -+## CURLMOPT_MAX_PIPELINE_LENGTH - --See CURLMOPT_MAXCONNECTS(3) -+**deprecated**. See CURLMOPT_MAX_PIPELINE_LENGTH(3) - --## CURLMOPT_PIPELINING -+## CURLMOPT_MAX_TOTAL_CONNECTIONS - --See CURLMOPT_PIPELINING(3) -+Max simultaneously open connections. See CURLMOPT_MAX_TOTAL_CONNECTIONS(3) - --## CURLMOPT_PIPELINING_SITE_BL -+## CURLMOPT_PIPELINING - --See CURLMOPT_PIPELINING_SITE_BL(3) -+Enable HTTP multiplexing. See CURLMOPT_PIPELINING(3) - - ## CURLMOPT_PIPELINING_SERVER_BL - --See CURLMOPT_PIPELINING_SERVER_BL(3) -+**deprecated**. See CURLMOPT_PIPELINING_SERVER_BL(3) - --## CURLMOPT_PUSHFUNCTION -+## CURLMOPT_PIPELINING_SITE_BL - --See CURLMOPT_PUSHFUNCTION(3) -+**deprecated**. See CURLMOPT_PIPELINING_SITE_BL(3) - - ## CURLMOPT_PUSHDATA - --See CURLMOPT_PUSHDATA(3) -+Pointer to pass to push callback. See CURLMOPT_PUSHDATA(3) - --## CURLMOPT_SOCKETFUNCTION -+## CURLMOPT_PUSHFUNCTION - --See CURLMOPT_SOCKETFUNCTION(3) -+Callback that approves or denies server pushes. See CURLMOPT_PUSHFUNCTION(3) - - ## CURLMOPT_SOCKETDATA - --See CURLMOPT_SOCKETDATA(3) -+Custom pointer passed to the socket callback. See CURLMOPT_SOCKETDATA(3) - --## CURLMOPT_TIMERFUNCTION -+## CURLMOPT_SOCKETFUNCTION - --See CURLMOPT_TIMERFUNCTION(3) -+Callback informed about what to wait for. See CURLMOPT_SOCKETFUNCTION(3) - - ## CURLMOPT_TIMERDATA - --See CURLMOPT_TIMERDATA(3) -+Custom pointer to pass to timer callback. See CURLMOPT_TIMERDATA(3) - --## CURLMOPT_MAX_CONCURRENT_STREAMS -+## CURLMOPT_TIMERFUNCTION - --See CURLMOPT_MAX_CONCURRENT_STREAMS(3) -+Callback to receive timeout values. See CURLMOPT_TIMERFUNCTION(3) -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -116,9 +120,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_socket.md b/docs/libcurl/curl_multi_socket.md -index 4c85d0199..5903a1e1f 100644 ---- a/docs/libcurl/curl_multi_socket.md -+++ b/docs/libcurl/curl_multi_socket.md -@@ -12,11 +12,12 @@ See-also: - - the hiperfifo.c example - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME - --curl_multi_socket - reads/writes available data -+curl_multi_socket - read/write available data - - # SYNOPSIS - -@@ -24,47 +25,39 @@ curl_multi_socket - reads/writes available data - #include - CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd, - int *running_handles); -- --CURLMcode curl_multi_socket_all(CURLM *multi_handle, -- int *running_handles); - ~~~ - - # DESCRIPTION - --These functions are deprecated. Do not use. See --curl_multi_socket_action(3) instead. -+This function is deprecated. Do not use. See curl_multi_socket_action(3) -+instead. - - At return, the integer **running_handles** points to contains the number of - still running easy handles within the multi handle. When this number reaches - zero, all transfers are complete/done. Note that when you call --curl_multi_socket_action(3) on a specific socket and the counter --decreases by one, it DOES NOT necessarily mean that this exact socket/transfer --is the one that completed. Use curl_multi_info_read(3) to figure out --which easy handle that completed. -- --The curl_multi_socket_action(3) functions inform the application about --updates in the socket (file descriptor) status by doing none, one, or multiple --calls to the socket callback function set with the --CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They --update the status with changes since the previous time the callback was --called. -- --Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option --with curl_multi_setopt(3). Your application then gets called with --information on how long to wait for socket actions at most before doing the --timeout action: call the curl_multi_socket_action(3) function with the --**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the --curl_multi_timeout(3) function to poll the value at any given time, but --for an event-based system using the callback is far better than relying on --polling the timeout value. -+curl_multi_socket(3) on a specific socket and the counter decreases by one, it -+DOES NOT necessarily mean that this exact socket/transfer is the one that -+completed. Use curl_multi_info_read(3) to figure out which easy handle that -+completed. -+ -+The curl_multi_socket(3) functions inform the application about updates in the -+socket (file descriptor) status by doing none, one, or multiple calls to the -+socket callback function set with the CURLMOPT_SOCKETFUNCTION(3) option to -+curl_multi_setopt(3). They update the status with changes since the previous -+time the callback was called. -+ -+Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option with -+curl_multi_setopt(3). Your application then gets called with information on -+how long to wait for socket actions at most before doing the timeout action: -+call the curl_multi_socket_action(3) function with the **sockfd** argument set -+to CURL_SOCKET_TIMEOUT. You can also use the curl_multi_timeout(3) function to -+poll the value at any given time, but for an event-based system using the -+callback is far better than relying on polling the timeout value. - - Usage of curl_multi_socket(3) is deprecated, whereas the function is --equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to --0. -+equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to 0. - --Force libcurl to (re-)check all its internal sockets and transfers instead of --just a single one by calling curl_multi_socket_all(3). Note that there --should not be any reason to use this function. -+# %PROTOCOLS% - - # EXAMPLE - -@@ -81,13 +74,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - --This function was added in libcurl 7.15.4, and is deemed stable since --7.16.0. -+curl_multi_socket(3) is deprecated, use curl_multi_socket_action(3) instead. - --curl_multi_socket(3) is deprecated, use --curl_multi_socket_action(3) instead! -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_socket_action.md b/docs/libcurl/curl_multi_socket_action.md -index c7faa7637..536bf3cb6 100644 ---- a/docs/libcurl/curl_multi_socket_action.md -+++ b/docs/libcurl/curl_multi_socket_action.md -@@ -12,11 +12,12 @@ See-also: - - the hiperfifo.c example - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME - --curl_multi_socket_action - reads/writes available data given an action -+curl_multi_socket_action - read/write available data given an action - - # SYNOPSIS - -@@ -95,6 +96,8 @@ callback has been told. - socket(s) that got action. If no activity is detected and the timeout expires, - call curl_multi_socket_action(3) with *CURL_SOCKET_TIMEOUT*. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -112,9 +115,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.15.4, and is deemed stable since 7.16.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_socket_all.md b/docs/libcurl/curl_multi_socket_all.md -index 4c85d0199..37a605bde 100644 ---- a/docs/libcurl/curl_multi_socket_all.md -+++ b/docs/libcurl/curl_multi_socket_all.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: curl_multi_socket -+Title: curl_multi_socket_all - Section: 3 - Source: libcurl - See-also: -@@ -12,18 +12,17 @@ See-also: - - the hiperfifo.c example - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME - --curl_multi_socket - reads/writes available data -+curl_multi_socket_all - reads/writes available data for all easy handles - - # SYNOPSIS - - ~~~c - #include --CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd, -- int *running_handles); - - CURLMcode curl_multi_socket_all(CURLM *multi_handle, - int *running_handles); -@@ -31,63 +30,32 @@ CURLMcode curl_multi_socket_all(CURLM *multi_handle, - - # DESCRIPTION - --These functions are deprecated. Do not use. See --curl_multi_socket_action(3) instead. -+This function is deprecated. Do not use. See curl_multi_socket_action(3) -+instead. - - At return, the integer **running_handles** points to contains the number of - still running easy handles within the multi handle. When this number reaches --zero, all transfers are complete/done. Note that when you call --curl_multi_socket_action(3) on a specific socket and the counter --decreases by one, it DOES NOT necessarily mean that this exact socket/transfer --is the one that completed. Use curl_multi_info_read(3) to figure out --which easy handle that completed. -- --The curl_multi_socket_action(3) functions inform the application about --updates in the socket (file descriptor) status by doing none, one, or multiple --calls to the socket callback function set with the --CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They --update the status with changes since the previous time the callback was --called. -- --Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option --with curl_multi_setopt(3). Your application then gets called with --information on how long to wait for socket actions at most before doing the --timeout action: call the curl_multi_socket_action(3) function with the --**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the --curl_multi_timeout(3) function to poll the value at any given time, but --for an event-based system using the callback is far better than relying on --polling the timeout value. -- --Usage of curl_multi_socket(3) is deprecated, whereas the function is --equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to --0. -+zero, all transfers are complete/done. - - Force libcurl to (re-)check all its internal sockets and transfers instead of --just a single one by calling curl_multi_socket_all(3). Note that there --should not be any reason to use this function. -+just a single one by calling curl_multi_socket_all(3). Note that there should -+not be any reason to use this function. -+ -+# %PROTOCOLS% - - # EXAMPLE - - ~~~c - int main(void) - { -- /* the event-library gets told when there activity on the socket 'fd', -- which we translate to a call to curl_multi_socket_action() */ - int running; - int rc; -- int fd; - CURLM *multi; -- rc = curl_multi_socket(multi, fd, &running); -+ rc = curl_multi_socket_all(multi, &running); - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.15.4, and is deemed stable since --7.16.0. -- --curl_multi_socket(3) is deprecated, use --curl_multi_socket_action(3) instead! -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_strerror.md b/docs/libcurl/curl_multi_strerror.md -index 4b53d6787..d419ab2e8 100644 ---- a/docs/libcurl/curl_multi_strerror.md -+++ b/docs/libcurl/curl_multi_strerror.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.12.0 - --- - - # NAME -@@ -30,6 +31,8 @@ const char *curl_multi_strerror(CURLMcode errornum); - This function returns a string describing the *CURLMcode* error code - passed in the argument *errornum*. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -44,9 +47,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.12.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_timeout.md b/docs/libcurl/curl_multi_timeout.md -index ed8a8acbc..de59c3920 100644 ---- a/docs/libcurl/curl_multi_timeout.md -+++ b/docs/libcurl/curl_multi_timeout.md -@@ -11,6 +11,7 @@ See-also: - - curl_multi_socket (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -48,6 +49,8 @@ Note: if libcurl returns a -1 timeout here, it just means that libcurl - currently has no stored timeout value. You must not wait too long (more than a - few seconds perhaps) before you call curl_multi_perform(3) again. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -82,9 +85,7 @@ out which sockets to wait for by calling curl_multi_fdset(3). - When there is activity or timeout, call curl_multi_perform(3) and then - loop - until all transfers are complete. - --# AVAILABILITY -- --This function was added in libcurl 7.15.4. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_wait.md b/docs/libcurl/curl_multi_wait.md -index de8e0ff1f..7e9553d76 100644 ---- a/docs/libcurl/curl_multi_wait.md -+++ b/docs/libcurl/curl_multi_wait.md -@@ -10,11 +10,12 @@ See-also: - - curl_multi_poll (3) - Protocol: - - All -+Added-in: 7.28.0 - --- - - # NAME - --curl_multi_wait - polls on all easy handles in a multi handle -+curl_multi_wait - poll on all easy handles in a multi handle - - # SYNOPSIS - -@@ -34,7 +35,7 @@ curl_multi_wait(3) polls all file descriptors used by the curl easy - handles contained in the given multi handle set. It blocks until activity is - detected on at least one of the handles or *timeout_ms* has passed. - Alternatively, if the multi handle has a pending internal timeout that has a --shorter expiry time than *timeout_ms*, that shorter time is be used -+shorter expiry time than *timeout_ms*, that shorter time is being used - instead to make sure timeout accuracy is reasonably kept. - - The calling application may pass additional *curl_waitfd* structures which -@@ -79,6 +80,8 @@ priority read events such as out of band data. - Bit flag to *curl_waitfd.events* indicating the socket should poll on - write events such as the socket being clear to write without blocking. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -113,9 +116,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.28.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_multi_waitfds.md b/docs/libcurl/curl_multi_waitfds.md -new file mode 100644 -index 000000000..0a8440eb4 ---- /dev/null -+++ b/docs/libcurl/curl_multi_waitfds.md -@@ -0,0 +1,112 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Title: curl_multi_waitfds -+Section: 3 -+Source: libcurl -+See-also: -+ - curl_multi_perform (3) -+ - curl_multi_poll (3) -+ - curl_multi_wait (3) -+ - curl_multi_fdset (3) -+Protocol: -+ - All -+Added-in: 8.8.0 -+--- -+ -+# NAME -+ -+curl_multi_waitfds - extract file descriptor information from a multi handle -+ -+# SYNOPSIS -+ -+~~~c -+#include -+#include -+ -+CURLMcode curl_multi_waitfds(CURLM *multi, -+ struct curl_waitfd *ufds, -+ unsigned int size, -+ unsigned int *fd_count); -+~~~ -+ -+# DESCRIPTION -+ -+This function extracts *curl_waitfd* structures which are similar to -+*poll(2)*'s *pollfd* structure from a given multi_handle. -+ -+These structures can be used for polling on multi_handle file descriptors in a -+fashion similar to curl_multi_poll(3). The curl_multi_perform(3) -+function should be called as soon as one of them is ready to be read from or -+written to. -+ -+libcurl fills provided *ufds* array up to the *size*. -+If a number of descriptors used by the multi_handle is greater than the -+*size* parameter then libcurl returns CURLM_OUT_OF_MEMORY error. -+ -+If the *fd_count* argument is not a null pointer, it points to a variable -+that on returns specifies the number of descriptors used by the multi_handle to -+be checked for being ready to read or write. -+ -+The client code can pass *size* equal to zero just to get the number of the -+descriptors and allocate appropriate storage for them to be used in a -+subsequent function call. -+ -+# %PROTOCOLS% -+ -+# EXAMPLE -+ -+~~~c -+#include -+ -+int main(void) -+{ -+ CURLMcode mc; -+ struct curl_waitfd *ufds; -+ -+ CURLM *multi = curl_multi_init(); -+ -+ do { -+ /* call curl_multi_perform() */ -+ -+ /* get the count of file descriptors from the transfers */ -+ unsigned int fd_count = 0; -+ -+ mc = curl_multi_waitfds(multi, NULL, 0, &fd_count); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); -+ break; -+ } -+ -+ if(!fd_count) -+ continue; /* no descriptors yet */ -+ -+ /* Allocate storage for our descriptors. -+ * Note that a better approach can be used to minimize allocations and -+ * deallocations, if needed, like pre-allocated or grow-only array. -+ */ -+ ufds = (struct curl_waitfd*)malloc(fd_count * sizeof(struct curl_waitfd)); -+ -+ /* get wait descriptors from the transfers and put them into array. */ -+ mc = curl_multi_waitfds(multi, ufds, fd_count, NULL); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); -+ free(ufds); -+ break; -+ } -+ -+ /* Do polling on descriptors in ufds */ -+ -+ free(ufds); -+ } while(!mc); -+} -+~~~ -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+**CURLMcode** type, general libcurl multi interface error code. See -+libcurl-errors(3) -diff --git a/docs/libcurl/curl_multi_wakeup.md b/docs/libcurl/curl_multi_wakeup.md -index cadaeaa31..a920847a6 100644 ---- a/docs/libcurl/curl_multi_wakeup.md -+++ b/docs/libcurl/curl_multi_wakeup.md -@@ -9,11 +9,12 @@ See-also: - - curl_multi_wait (3) - Protocol: - - All -+Added-in: 7.68.0 - --- - - # NAME - --curl_multi_wakeup - wakes up a sleeping curl_multi_poll call -+curl_multi_wakeup - wake up a sleeping curl_multi_poll call - - # SYNOPSIS - -@@ -38,6 +39,8 @@ that multiple calls to this function wake up the same waiting operation. - - This function has no effect on curl_multi_wait(3) calls. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -84,9 +87,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.68.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_pushheader_byname.md b/docs/libcurl/curl_pushheader_byname.md -index 700f51106..d066ea7b8 100644 ---- a/docs/libcurl/curl_pushheader_byname.md -+++ b/docs/libcurl/curl_pushheader_byname.md -@@ -9,6 +9,7 @@ See-also: - - curl_pushheader_bynum (3) - Protocol: - - HTTP -+Added-in: 7.44.0 - --- - - # NAME -@@ -35,6 +36,8 @@ not have to loop through all headers to find the one it is interested in. The - data this function points to is freed when this callback returns. If more than - one header field use the same name, this returns only the first one. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.44.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_pushheader_bynum.md b/docs/libcurl/curl_pushheader_bynum.md -index f39836fc5..12555c57f 100644 ---- a/docs/libcurl/curl_pushheader_bynum.md -+++ b/docs/libcurl/curl_pushheader_bynum.md -@@ -9,6 +9,7 @@ See-also: - - curl_pushheader_byname (3) - Protocol: - - HTTP -+Added-in: 7.44.0 - --- - - # NAME -@@ -34,6 +35,8 @@ the incoming server push request or NULL. The data pointed to is freed by - libcurl when this callback returns. The returned pointer points to a - "name:value" string that gets freed when this callback returns. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.44.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_share_cleanup.md b/docs/libcurl/curl_share_cleanup.md -index 36acc6f08..afb06d008 100644 ---- a/docs/libcurl/curl_share_cleanup.md -+++ b/docs/libcurl/curl_share_cleanup.md -@@ -9,11 +9,12 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME - --curl_share_cleanup - Clean up a shared object -+curl_share_cleanup - close a shared object - - # SYNOPSIS - -@@ -31,6 +32,11 @@ when this function has been called. - Passing in a NULL pointer in *share_handle* makes this function return - immediately with no action. - -+Any use of the **share_handle** after this function has been called and have -+returned, is illegal. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -44,9 +50,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_share_init.md b/docs/libcurl/curl_share_init.md -index 2e74dfed8..deb61733c 100644 ---- a/docs/libcurl/curl_share_init.md -+++ b/docs/libcurl/curl_share_init.md -@@ -9,11 +9,12 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME - --curl_share_init - Create a shared object -+curl_share_init - create a share object - - # SYNOPSIS - -@@ -35,6 +36,8 @@ This *share handle* is what you pass to curl using the - CURLOPT_SHARE(3) option with curl_easy_setopt(3), to make that - specific curl handle use the data in this share. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -48,9 +51,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_share_setopt.md b/docs/libcurl/curl_share_setopt.md -index 166f5f6ba..a15955e4c 100644 ---- a/docs/libcurl/curl_share_setopt.md -+++ b/docs/libcurl/curl_share_setopt.md -@@ -9,11 +9,12 @@ See-also: - - curl_share_init (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME - --curl_share_setopt - Set options for a shared object -+curl_share_setopt - set options for a shared object - - # SYNOPSIS - -@@ -49,6 +50,8 @@ See CURLSHOPT_UNSHARE(3). - - See CURLSHOPT_USERDATA(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_share_strerror.md b/docs/libcurl/curl_share_strerror.md -index 9137115a2..9c45278f5 100644 ---- a/docs/libcurl/curl_share_strerror.md -+++ b/docs/libcurl/curl_share_strerror.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.12.0 - --- - - # NAME -@@ -30,6 +31,8 @@ const char *curl_share_strerror(CURLSHcode errornum); - The curl_share_strerror(3) function returns a string describing the - *CURLSHcode* error code passed in the argument *errornum*. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -43,9 +46,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This function was added in libcurl 7.12.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_slist_append.md b/docs/libcurl/curl_slist_append.md -index dd3dabb77..27ec45da1 100644 ---- a/docs/libcurl/curl_slist_append.md -+++ b/docs/libcurl/curl_slist_append.md -@@ -8,6 +8,7 @@ See-also: - - curl_slist_free_all (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -34,6 +35,8 @@ returns. curl_slist_append(3) copies the string. - The list should be freed again (after usage) with - curl_slist_free_all(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_slist_free_all.md b/docs/libcurl/curl_slist_free_all.md -index 5f54fabc1..91491aa6c 100644 ---- a/docs/libcurl/curl_slist_free_all.md -+++ b/docs/libcurl/curl_slist_free_all.md -@@ -8,6 +8,7 @@ See-also: - - curl_slist_append (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -30,6 +31,11 @@ linked list. - Passing in a NULL pointer in *list* makes this function return immediately - with no action. - -+Any use of the **list** after this function has been called and have returned, -+is illegal. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_strequal.md b/docs/libcurl/curl_strequal.md -index 70de794aa..e7270d874 100644 ---- a/docs/libcurl/curl_strequal.md -+++ b/docs/libcurl/curl_strequal.md -@@ -5,15 +5,17 @@ Title: curl_strequal - Section: 3 - Source: libcurl - See-also: -+ - curl_strnequal (3) - - strcasecmp (3) - - strcmp (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_strequal, curl_strnequal - case insensitive string comparisons -+curl_strequal - compare two strings ignoring case - - # SYNOPSIS - -@@ -21,21 +23,23 @@ curl_strequal, curl_strnequal - case insensitive string comparisons - #include - - int curl_strequal(const char *str1, const char *str2); --int curl_strnequal(const char *str1, const char *str2, size_t length); - ~~~ - - # DESCRIPTION - --The curl_strequal(3) function compares the two strings *str1* and --*str2*, ignoring the case of the characters. It returns a non-zero (TRUE) --integer if the strings are identical. -+The curl_strequal(3) function compares the two strings *str1* and *str2*, -+ignoring the case of the characters. It returns a non-zero (TRUE) integer if -+the strings are identical. - --The **curl_strnequal()** function is similar, except it only compares the --first *length* characters of *str1*. -+This function uses plain ASCII based comparisons completely disregarding the -+locale - contrary to how **strcasecmp** and other system case insensitive -+string comparisons usually work. - --These functions are provided by libcurl to enable applications to compare --strings in a truly portable manner. There are no standard portable case --insensitive string comparison functions. These two work on all platforms. -+This function is provided by libcurl to enable applications to compare strings -+in a truly portable manner. There are no standard portable case insensitive -+string comparison functions. This function works on all platforms. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -45,14 +49,10 @@ int main(int argc, char **argv) - const char *name = "compare"; - if(curl_strequal(name, argv[1])) - printf("Name and input matches\n"); -- if(curl_strnequal(name, argv[1], 5)) -- printf("Name and input matches in the 5 first bytes\n"); - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_strnequal.md b/docs/libcurl/curl_strnequal.md -index 70de794aa..db42bcdf8 100644 ---- a/docs/libcurl/curl_strnequal.md -+++ b/docs/libcurl/curl_strnequal.md -@@ -1,41 +1,48 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: curl_strequal -+Title: curl_strnequal - Section: 3 - Source: libcurl - See-also: -+ - curl_strequal (3) - - strcasecmp (3) - - strcmp (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_strequal, curl_strnequal - case insensitive string comparisons -+curl_strnequal - compare two strings ignoring case - - # SYNOPSIS - - ~~~c - #include - --int curl_strequal(const char *str1, const char *str2); - int curl_strnequal(const char *str1, const char *str2, size_t length); - ~~~ - - # DESCRIPTION - --The curl_strequal(3) function compares the two strings *str1* and --*str2*, ignoring the case of the characters. It returns a non-zero (TRUE) --integer if the strings are identical. -+The curl_strnequal(3) function compares the two strings *str1* and *str2*, -+ignoring the case of the characters. It returns a non-zero (TRUE) integer if -+the strings are identical. - --The **curl_strnequal()** function is similar, except it only compares the --first *length* characters of *str1*. -+This function compares no more than the first *length* bytes of *str1* and -+*str2*. - --These functions are provided by libcurl to enable applications to compare --strings in a truly portable manner. There are no standard portable case --insensitive string comparison functions. These two work on all platforms. -+This function uses plain ASCII based comparisons completely disregarding the -+locale - contrary to how **strcasecmp** and other system case insensitive -+string comparisons usually work. -+ -+This function is provided by libcurl to enable applications to compare strings -+in a truly portable manner. There are no standard portable case insensitive -+string comparison functions. This function works on all platforms. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -43,16 +50,12 @@ insensitive string comparison functions. These two work on all platforms. - int main(int argc, char **argv) - { - const char *name = "compare"; -- if(curl_strequal(name, argv[1])) -- printf("Name and input matches\n"); - if(curl_strnequal(name, argv[1], 5)) - printf("Name and input matches in the 5 first bytes\n"); - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_unescape.md b/docs/libcurl/curl_unescape.md -index adcce8b14..2600f1436 100644 ---- a/docs/libcurl/curl_unescape.md -+++ b/docs/libcurl/curl_unescape.md -@@ -11,11 +11,12 @@ See-also: - - curl_free (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME - --curl_unescape - URL decodes the given string -+curl_unescape - URL decode a string - - # SYNOPSIS - -@@ -27,7 +28,7 @@ char *curl_unescape(const char *input, int length); - - # DESCRIPTION - --Obsolete function. Use curl_easy_unescape(3) instead. -+Deprecated. Use curl_easy_unescape(3) instead. - - This function converts the URL encoded string **input** to a "plain string" - and return that as a new allocated string. All input characters that are URL -@@ -39,6 +40,8 @@ strlen() on **input** to find out the size. - - You must curl_free(3) the returned string when you are done with it. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,11 +60,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Since 7.15.4, curl_easy_unescape(3) should be used. This function might - be removed in a future release. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - A pointer to a null-terminated string or NULL if it failed. -diff --git a/docs/libcurl/curl_url.md b/docs/libcurl/curl_url.md -index acab43d88..5872134e1 100644 ---- a/docs/libcurl/curl_url.md -+++ b/docs/libcurl/curl_url.md -@@ -13,11 +13,12 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME - --curl_url - returns a new URL handle -+curl_url - create a URL handle - - # SYNOPSIS - -@@ -37,6 +38,8 @@ single URL. When the object is first created, there is of course no components - stored. They are then set in the object with the curl_url_set(3) - function. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_url_cleanup.md b/docs/libcurl/curl_url_cleanup.md -index ab0acdce8..36455fc0b 100644 ---- a/docs/libcurl/curl_url_cleanup.md -+++ b/docs/libcurl/curl_url_cleanup.md -@@ -12,6 +12,7 @@ See-also: - - curl_url_set (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -28,11 +29,16 @@ void curl_url_cleanup(CURLU *handle); - - # DESCRIPTION - --Frees all the resources associated with the given *CURLU* handle! -+Frees all the resources associated with the given *CURLU* handle. - - Passing in a NULL pointer in *handle* makes this function return - immediately with no action. - -+Any use of the **handle** after this function has been called and have -+returned, is illegal. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -44,9 +50,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_url_dup.md b/docs/libcurl/curl_url_dup.md -index 43b54eb29..28a661a47 100644 ---- a/docs/libcurl/curl_url_dup.md -+++ b/docs/libcurl/curl_url_dup.md -@@ -12,6 +12,7 @@ See-also: - - curl_url_set (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -32,6 +33,8 @@ Duplicates the URL object the input *CURLU* *inhandle* identifies and - returns a pointer to the copy as a new *CURLU* handle. The new handle also - needs to be freed with curl_url_cleanup(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -42,16 +45,14 @@ int main(void) - CURLU *url2; - rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0); - if(!rc) { -- url2 = curl_url_dup(url); /* clone it! */ -+ url2 = curl_url_dup(url); /* clone it */ - curl_url_cleanup(url2); - } - curl_url_cleanup(url); - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_url_get.md b/docs/libcurl/curl_url_get.md -index 2f3b89b5e..e7aa6baa5 100644 ---- a/docs/libcurl/curl_url_get.md -+++ b/docs/libcurl/curl_url_get.md -@@ -13,6 +13,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -113,16 +114,47 @@ punycode. - - (Added in curl 8.3.0) - -+## CURLU_GET_EMPTY -+ -+When this flag is used in curl_url_get(), it makes the function return empty -+query and fragments parts or when used in the full URL. By default, libcurl -+otherwise considers empty parts non-existing. -+ -+An empty query part is one where this is nothing following the question mark -+(before the possible fragment). An empty fragments part is one where there is -+nothing following the hash sign. -+ -+(Added in curl 8.8.0) -+ -+## CURLU_NO_GUESS_SCHEME -+ -+When this flag is used in curl_url_get(), it treats the scheme as non-existing -+if it was set as a result of a previous guess; when CURLU_GUESS_SCHEME was -+used parsing a URL. -+ -+Using this flag when getting CURLUPART_SCHEME if the scheme was set as the -+result of a guess makes curl_url_get() return CURLUE_NO_SCHEME. -+ -+Using this flag when getting CURLUPART_URL if the scheme was set as the result -+of a guess makes curl_url_get() return the full URL without the scheme -+component. Such a URL can then only be parsed with curl_url_set() if -+CURLU_GUESS_SCHEME is used. -+ -+(Added in curl 8.9.0) -+ - # PARTS - - ## CURLUPART_URL - --When asked to return the full URL, curl_url_get(3) returns a normalized --and possibly cleaned up version using all available URL parts. -+When asked to return the full URL, curl_url_get(3) returns a normalized and -+possibly cleaned up version using all available URL parts. -+ -+We advise using the *CURLU_PUNYCODE* option to get the URL as "normalized" as -+possible since IDN allows hostnames to be written in many different ways that -+still end up the same punycode version. - --We advise using the *CURLU_PUNYCODE* option to get the URL as "normalized" --as possible since IDN allows hostnames to be written in many different ways --that still end up the same punycode version. -+Zero-length queries and fragments are excluded from the URL unless -+CURLU_GET_EMPTY is set. - - ## CURLUPART_SCHEME - -@@ -169,7 +201,8 @@ The initial question mark that denotes the beginning of the query part is a - delimiter only. It is not part of the query contents. - - A not-present query returns *part* set to NULL. --A zero-length query returns *part* as a zero-length string. -+ -+A zero-length query returns *part* as NULL unless CURLU_GET_EMPTY is set. - - The query part gets pluses converted to space when asked to URL decode on get - with the CURLU_URLDECODE bit. -@@ -179,6 +212,12 @@ with the CURLU_URLDECODE bit. - The initial hash sign that denotes the beginning of the fragment is a - delimiter only. It is not part of the fragment contents. - -+A not-present fragment returns *part* set to NULL. -+ -+A zero-length fragment returns *part* as NULL unless CURLU_GET_EMPTY is set. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -199,9 +238,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_url_set.md b/docs/libcurl/curl_url_set.md -index 328937c69..b041d756d 100644 ---- a/docs/libcurl/curl_url_set.md -+++ b/docs/libcurl/curl_url_set.md -@@ -13,6 +13,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.78.0 - --- - - # NAME -@@ -38,35 +39,30 @@ handle previously created by curl_url(3) or curl_url_dup(3). - This function sets or updates individual URL components, or parts, held by the - URL object the handle identifies. - --The *part* argument should identify the particular URL part (see list --below) to set or change, with *content* pointing to a null-terminated --string with the new contents for that URL part. The contents should be in the --form and encoding they would use in a URL: URL encoded. -+The *part* argument should identify the particular URL part (see list below) -+to set or change, with *content* pointing to a null-terminated string with the -+new contents for that URL part. The contents should be in the form and -+encoding they would use in a URL: URL encoded. - --When setting part in the URL object that was previously already set, it -+When setting a part in the URL object that was previously already set, it - replaces the data that was previously stored for that part with the new - *content*. - - The caller does not have to keep *content* around after a successful call - as this function copies the content. - --Setting a part to a NULL pointer removes that part's contents from the --*CURLU* handle. -- --By default, this API only accepts URLs using schemes for protocols that are --supported built-in. To make libcurl parse URLs generically even for schemes it --does not know about, the **CURLU_NON_SUPPORT_SCHEME** flags bit must be --set. Otherwise, this function returns *CURLUE_UNSUPPORTED_SCHEME* for URL --schemes it does not recognize. -+Setting a part to a NULL pointer removes that part's contents from the *CURLU* -+handle. - - This function has an 8 MB maximum length limit for all provided input strings. - In the real world, excessively long fields in URLs cause problems even if this --API accepts them. -+function accepts them. - --When setting or updating contents of individual URL parts, this API might --accept data that would not be otherwise possible to set in the string when it --gets populated as a result of a full URL parse. Beware. If done so, extracting --a full URL later on from such components might render an invalid URL. -+When setting or updating contents of individual URL parts, curl_url_set(3) -+might accept data that would not be otherwise possible to set in the string -+when it gets populated as a result of a full URL parse. Beware. If done so, -+extracting a full URL later on from such components might render an invalid -+URL. - - The *flags* argument is a bitmask with independent features. - -@@ -80,13 +76,23 @@ populated with a URL, the new URL can be relative to the previous. - When successfully setting a new URL, relative or absolute, the handle contents - is replaced with the components of the newly set URL. - --Pass a pointer to a null-terminated string to the *url* parameter. The --string must point to a correctly formatted "RFC 3986+" URL or be a NULL --pointer. -+Pass a pointer to a null-terminated string to the *url* parameter. The string -+must point to a correctly formatted "RFC 3986+" URL or be a NULL pointer. The -+URL parser only understands and parses the subset of URLS that are -+"hierarchical" and therefore contain a :// separator - not the ones that are -+normally specified with only a colon separator. -+ -+By default this API only parses URLs using schemes for protocols that are -+supported built-in. To make libcurl parse URLs generically even for schemes it -+does not know about, the **CURLU_NON_SUPPORT_SCHEME** flags bit must be set. -+Otherwise, this function returns *CURLUE_UNSUPPORTED_SCHEME* for URL schemes -+it does not recognize. - - Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed in - the URL. - -+When a full URL is set (parsed), the hostname component is stored URL decoded. -+ - ## CURLUPART_SCHEME - - Scheme cannot be URL decoded on set. libcurl only accepts setting schemes up -@@ -94,8 +100,14 @@ to 40 bytes long. - - ## CURLUPART_USER - -+If only the user part is set and not the password, the URL is represented with -+a blank password. -+ - ## CURLUPART_PASSWORD - -+If only the password part is set and not the user, the URL is represented with -+a blank user. -+ - ## CURLUPART_OPTIONS - - The options field is an optional field that might follow the password in the -@@ -110,6 +122,9 @@ encoded as your locale says or UTF-8 (when WinIDN is used). If it is a - bracketed IPv6 numeric address it may contain a zone id (or you can use - *CURLUPART_ZONEID*). - -+Note that if you set an IPv6 address, it gets ruined and causes an error if -+you also set the CURLU_URLENCODE flag. -+ - Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed to set. - - ## CURLUPART_ZONEID -@@ -157,17 +172,19 @@ first '=' symbol is not URL encoded. - - ## CURLU_NON_SUPPORT_SCHEME - --If set, allows curl_url_set(3) to set a non-supported scheme. -+If set, allows curl_url_set(3) to set a non-supported scheme. It then of -+course cannot know if the provided scheme is a valid one or not. - - ## CURLU_URLENCODE - - When set, curl_url_set(3) URL encodes the part on entry, except for --scheme, port and URL. -+**scheme**, **port** and **URL**. - - When setting the path component with URL encoding enabled, the slash character --is be skipped. -+is skipped. - --The query part gets space-to-plus conversion before the URL conversion. -+The query part gets space-to-plus converted before the URL conversion is -+applied. - - This URL encoding is charset unaware and converts the input in a byte-by-byte - manner. -@@ -175,8 +192,8 @@ manner. - ## CURLU_DEFAULT_SCHEME - - If set, allows the URL to be set without a scheme and then sets that to the --default scheme: HTTPS. Overrides the *CURLU_GUESS_SCHEME* option if both --are set. -+default scheme: HTTPS. Overrides the *CURLU_GUESS_SCHEME* option if both are -+set. - - ## CURLU_GUESS_SCHEME - -@@ -186,6 +203,14 @@ subdomain name matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that scheme is - used, otherwise it picks HTTP. Conflicts with the *CURLU_DEFAULT_SCHEME* - option which takes precedence if both are set. - -+If guessing is not allowed and there is no default scheme set, trying to parse -+a URL without a scheme returns error. -+ -+If the scheme ends up set as a result of guessing, i.e. it is not actually -+present in the parsed URL, it can later be figured out by using the -+**CURLU_NO_GUESS_SCHEME** flag when subsequently getting the URL or the scheme -+with curl_url_get(3). -+ - ## CURLU_NO_AUTHORITY - - If set, skips authority checks. The RFC allows individual schemes to omit the -@@ -217,6 +242,8 @@ If set, the URL parser does not accept embedded credentials for the - **CURLUPART_URL**, and instead returns **CURLUE_USER_NOT_ALLOWED** for - such URLs. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -233,9 +260,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_url_strerror.md b/docs/libcurl/curl_url_strerror.md -index a57e19df1..33cdb148d 100644 ---- a/docs/libcurl/curl_url_strerror.md -+++ b/docs/libcurl/curl_url_strerror.md -@@ -13,6 +13,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.80.0 - --- - - # NAME -@@ -32,6 +33,8 @@ const char *curl_url_strerror(CURLUcode errornum); - This function returns a string describing the CURLUcode error code passed in - the argument *errornum*. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -46,9 +49,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.80.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_version.md b/docs/libcurl/curl_version.md -index 48a102f09..25c5eb989 100644 ---- a/docs/libcurl/curl_version.md -+++ b/docs/libcurl/curl_version.md -@@ -8,6 +8,7 @@ See-also: - - curl_version_info (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -27,7 +28,9 @@ char *curl_version(); - Returns a human readable string with the version number of libcurl and some of - its important components (like OpenSSL version). - --We recommend using curl_version_info(3) instead! -+We recommend using curl_version_info(3) instead. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -38,9 +41,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_version_info.md b/docs/libcurl/curl_version_info.md -index 43365ac6d..271e935ca 100644 ---- a/docs/libcurl/curl_version_info.md -+++ b/docs/libcurl/curl_version_info.md -@@ -8,6 +8,7 @@ See-also: - - curl_version (3) - Protocol: - - All -+Added-in: 7.10.0 - --- - - # NAME -@@ -104,6 +105,9 @@ typedef struct { - /* when 'age' is CURLVERSION_ELEVENTH or higher (>= 7.87.0), the members - below exist */ - const char *const *feature_names; /* Feature names. */ -+ /* when 'age' is CURLVERSION_TWELFTH or higher (>= 8.8.0), the members -+ below exist */ -+ const char *const *rtmp_version; /* human readable string */ - } curl_version_info_data; - ~~~ - -@@ -112,13 +116,13 @@ new the libcurl you are using is. You are however guaranteed to get a struct - that you have a matching struct for in the header, as you tell libcurl your - "age" with the input argument. - --*version* is just an ascii string for the libcurl version. -+*version* is just an ASCII string for the libcurl version. - - *version_num* is a 24 bit number created like this: \<8 bits major number\> | - \<8 bits minor number\> | \<8 bits patch number\>. Version 7.9.8 is therefore - returned as 0x070908. - --*host* is an ascii string showing what host information that this libcurl -+*host* is an ASCII string showing what host information that this libcurl - was built for. As discovered by a configure script or set by the build - environment. - -@@ -173,6 +177,12 @@ supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0) - - libcurl was built with debug capabilities (added in 7.10.6) - -+## ECH -+ -+*features* mask bit: non-existent -+ -+libcurl was built with ECH support (experimental, added in 8.8.0) -+ - ## gsasl - - *features* mask bit: CURL_VERSION_GSASL -@@ -267,7 +277,7 @@ supports HTTP NTLM (added in 7.10.6) - *features* mask bit: CURL_VERSION_NTLM_WB - - libcurl was built with support for NTLM delegation to a winbind helper. --(Added in 7.22.0) -+(Added in 7.22.0) This feature was removed from curl in 8.8.0. - - ## PSL - -@@ -360,6 +370,8 @@ supports HTTP GSS-Negotiate (added in 7.10.6, deprecated in 7.38.0) - - supports Kerberos V4 (when using FTP). Legacy bit. Deprecated since 7.33.0. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -373,11 +385,8 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - - A pointer to a curl_version_info_data struct. --curl_version(3) -diff --git a/docs/libcurl/curl_ws_meta.md b/docs/libcurl/curl_ws_meta.md -index a60ce1d66..f95f25e80 100644 ---- a/docs/libcurl/curl_ws_meta.md -+++ b/docs/libcurl/curl_ws_meta.md -@@ -12,6 +12,7 @@ See-also: - - libcurl-ws (3) - Protocol: - - WS -+Added-in: 7.86.0 - --- - - # NAME -@@ -97,6 +98,8 @@ This transfer is now closed. - - This as an incoming ping message, that expects a pong response. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -132,9 +135,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.86.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_ws_recv.md b/docs/libcurl/curl_ws_recv.md -index 38a8a2abc..c13d74a5c 100644 ---- a/docs/libcurl/curl_ws_recv.md -+++ b/docs/libcurl/curl_ws_recv.md -@@ -12,6 +12,7 @@ See-also: - - libcurl-ws (3) - Protocol: - - WS -+Added-in: 7.86.0 - --- - - # NAME -@@ -36,12 +37,16 @@ Retrieves as much as possible of a received WebSocket data fragment into the - number of bytes actually stored. - - If there is more fragment data to deliver than what fits in the provided --*buffer*, libcurl returns a full buffer and the application needs to call --this function again to continue draining the buffer. -+*buffer*, libcurl returns a full buffer and the application needs to call this -+function again to continue draining the buffer. - --The *meta* pointer gets set to point to a *const struct curl_ws_frame* --that contains information about the received data. See the --curl_ws_meta(3) for details on that struct. -+If the function call is successful, the *meta* pointer gets set to point to a -+*const struct curl_ws_frame* that contains information about the received -+data. That struct must not be freed and its contents must not be relied upon -+anymore once another WebSocket function is called. See the curl_ws_meta(3) for -+details on that struct.a -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -60,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.86.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/curl_ws_send.md b/docs/libcurl/curl_ws_send.md -index ddb4f8744..262250b54 100644 ---- a/docs/libcurl/curl_ws_send.md -+++ b/docs/libcurl/curl_ws_send.md -@@ -12,6 +12,7 @@ See-also: - - libcurl-ws (3) - Protocol: - - WS -+Added-in: 7.86.0 - --- - - # NAME -@@ -52,6 +53,10 @@ If **CURLWS_RAW_MODE** is enabled in CURLOPT_WS_OPTIONS(3), the - To send a message consisting of multiple frames, set the *CURLWS_CONT* bit - in all frames except the final one. - -+Warning: while it is possible to invoke this function from a callback, -+such a call is blocking in this situation, e.g. only returns after all data -+has been sent or an error is encountered. -+ - # FLAGS - - ## CURLWS_TEXT -@@ -89,6 +94,8 @@ fragment like this, the *fragsize* must be provided with the total - expected fragment size in the first call and it needs to be zero in subsequent - calls. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -111,9 +118,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.86.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/libcurl-easy.md b/docs/libcurl/libcurl-easy.md -index 1286f4113..782108835 100644 ---- a/docs/libcurl/libcurl-easy.md -+++ b/docs/libcurl/libcurl-easy.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: libcurl -+Title: libcurl-easy - Section: 3 - Source: libcurl - See-also: -@@ -13,6 +13,7 @@ See-also: - - libcurl-multi (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -27,28 +28,27 @@ interface functions you use. Use curl_easy_init(3) to get the handle. - - You continue by setting all the options you want in the upcoming transfer, the - most important among them is the URL itself (you cannot transfer anything --without a specified URL as you may have figured out yourself). You might want --to set some callbacks as well that are called from the library when data is --available etc. curl_easy_setopt(3) is used for all this. -- --CURLOPT_URL(3) is the only option you really must set, as otherwise --there can be no transfer. Another commonly used option is --CURLOPT_VERBOSE(3) that helps you see what libcurl is doing under the --hood, which is useful when debugging for example. The --curl_easy_setopt(3) man page has a full index of the almost 300 -+without a specified URL). You might want to set some callbacks as well that -+are called from the library when data is available etc. For example -+CURLOPT_WRITEFUNCTION(3). curl_easy_setopt(3) is used for all this. -+ -+CURLOPT_URL(3) is the only option you really must set, as otherwise there can -+be no transfer. Another commonly used option is CURLOPT_VERBOSE(3) that helps -+you see what libcurl is doing under the hood, which is useful when debugging -+for example. The curl_easy_setopt(3) man page has a full index of the over 300 - available options. - - If you at any point would like to blank all previously set options for a --single easy handle, you can call curl_easy_reset(3) and you can also --make a clone of an easy handle (with all its set options) using -+single easy handle, you can call curl_easy_reset(3) and you can also make a -+clone of an easy handle (with all its set options) using - curl_easy_duphandle(3). - - When all is setup, you tell libcurl to perform the transfer using --curl_easy_perform(3). It performs the entire transfer operation and does --not return until it is done (successfully or not). -+curl_easy_perform(3). It performs the entire transfer operation and does not -+return until it is done (successfully or not). - - After the transfer has been made, you can set new options and make another - transfer, or if you are done, cleanup the session by calling --curl_easy_cleanup(3). If you want persistent connections, you do not --cleanup immediately, but instead run ahead and perform other transfers using --the same easy handle. -+curl_easy_cleanup(3). If you want persistent connections, you do not cleanup -+immediately, but instead run ahead and perform other transfers using the same -+easy handle. -diff --git a/docs/libcurl/libcurl-env-dbg.md b/docs/libcurl/libcurl-env-dbg.md -index 2ab8c2b95..73217ca20 100644 ---- a/docs/libcurl/libcurl-env-dbg.md -+++ b/docs/libcurl/libcurl-env-dbg.md -@@ -8,6 +8,7 @@ See-also: - - libcurl-env (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -63,6 +64,15 @@ Trace logging behavior as an alternative to calling curl_global_trace(3). - - Example: **CURL_DEBUG=http/2** means trace details about HTTP/2 handling. - -+In the curl command line tool, built with `--enable-debug`, this environment -+variable adds to arguments like `--verbose`, `-vvv`. At least a single `-v` -+is needed to make the run emit trace output, but when it does, the contents -+of `CURL_DEBUG` are added and can override existing options. -+ -+Example: **CURL_DEBUG=tcp,-http/2 curl -vv url** means trace protocol details, -+triggered by `-vv`, add tracing of TCP in addition and remove tracing of -+HTTP/2. -+ - ## CURL_DEBUG_SIZE - - Fake the size returned by CURLINFO_HEADER_SIZE and CURLINFO_REQUEST_SIZE. -@@ -97,7 +107,7 @@ the current. - - ## CURL_TIME - --Fake unix timestamp to use for AltSvc, HSTS and CURLINFO variables that are -+Fake Unix timestamp to use for AltSvc, HSTS and CURLINFO variables that are - time related. - - This variable can also be used to fake the data returned by some CURLINFO -@@ -110,10 +120,6 @@ LDAP tracing is enabled if this variable exists and its value is 1 or greater. - - OpenLDAP tracing is separate. Refer to CURL_OPENLDAP_TRACE. - --## CURL_NTLM_WB_FILE -- --Debug-version of the *ntlm-wb* executable. -- - ## CURL_OPENLDAP_TRACE - - OpenLDAP tracing is enabled if this variable exists and its value is 1 or -@@ -123,3 +129,16 @@ greater. There is a number of debug levels, refer to *openldap.c* comments. - - Used to influence the buffer chunk size used for WebSocket encoding and - decoding. -+ -+## CURL_FORBID_REUSE -+ -+Used to set the CURLOPT_FORBID_REUSE flag on each transfer initiated -+by the curl command line tool. The value of the environment variable -+does not matter. -+ -+## CURL_GRACEFUL_SHUTDOWN -+ -+Make a blocking, graceful shutdown of all remaining connections when -+a multi handle is destroyed. This implicitly triggers for easy handles -+that are run via easy_perform. The value of the environment variable -+gives the shutdown timeout in milliseconds. -diff --git a/docs/libcurl/libcurl-env.md b/docs/libcurl/libcurl-env.md -index 0db69ff95..70b41d12d 100644 ---- a/docs/libcurl/libcurl-env.md -+++ b/docs/libcurl/libcurl-env.md -@@ -8,6 +8,7 @@ See-also: - - libcurl-env-dbg (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -51,7 +52,7 @@ this variable's selection is used. Setting a name that is not a built-in - alternative makes libcurl stay with the default. - - SSL backend names (case-insensitive): BearSSL, GnuTLS, mbedTLS, --nss, OpenSSL, rustls, Schannel, Secure-Transport, wolfSSL -+nss, OpenSSL, Rustls, Schannel, Secure-Transport, wolfSSL - - ## `HOME` - -diff --git a/docs/libcurl/libcurl-errors.md b/docs/libcurl/libcurl-errors.md -index af16b99de..1b5e41112 100644 ---- a/docs/libcurl/libcurl-errors.md -+++ b/docs/libcurl/libcurl-errors.md -@@ -14,6 +14,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -59,7 +60,7 @@ The URL was not properly formatted. - - ## CURLE_NOT_BUILT_IN (4) - --A requested feature, protocol or option was not found built-in in this libcurl -+A requested feature, protocol or option was not found built into this libcurl - due to a build-time decision. This means that a feature or option was not - enabled or explicitly disabled when libcurl was built and in order to get it - to function you have to get a rebuilt libcurl. -@@ -487,6 +488,10 @@ An internal call to poll() or select() returned error that is not recoverable. - - A value or data field grew larger than allowed. - -+## CURLE_ECH_REQUIRED (101)" -+ -+ECH was attempted but failed. -+ - # CURLMcode - - This is the generic return code used by functions in the libcurl multi -@@ -520,7 +525,7 @@ You are doomed. - - ## CURLM_INTERNAL_ERROR (4) - --This can only be returned if libcurl bugs. Please report it to us! -+This can only be returned if libcurl bugs. Please report it to us. - - ## CURLM_BAD_SOCKET (5) - -diff --git a/docs/libcurl/libcurl-multi.md b/docs/libcurl/libcurl-multi.md -index cf3bc5693..3becb648d 100644 ---- a/docs/libcurl/libcurl-multi.md -+++ b/docs/libcurl/libcurl-multi.md -@@ -10,6 +10,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -diff --git a/docs/libcurl/libcurl-security.md b/docs/libcurl/libcurl-security.md -index 93a116136..e1301698b 100644 ---- a/docs/libcurl/libcurl-security.md -+++ b/docs/libcurl/libcurl-security.md -@@ -8,6 +8,7 @@ See-also: - - libcurl-thread (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -121,7 +122,7 @@ user running the libcurl application, SCP: or SFTP: URLs could access password - or private-key protected resources, - e.g. **sftp://user@some-internal-server/etc/passwd** - --The CURLOPT_REDIR_PROTOCOLS(3) and CURLOPT_NETRC(3) options can be -+The CURLOPT_REDIR_PROTOCOLS_STR(3) and CURLOPT_NETRC(3) options can be - used to mitigate against this kind of attack. - - A redirect can also specify a location available only on the machine running -@@ -132,7 +133,7 @@ E.g. **http://127.0.0.1/** or **http://intranet/delete-stuff.cgi?delete=all** or - Applications can mitigate against this by disabling - CURLOPT_FOLLOWLOCATION(3) and handling redirects itself, sanitizing URLs - as necessary. Alternately, an app could leave CURLOPT_FOLLOWLOCATION(3) --enabled but set CURLOPT_REDIR_PROTOCOLS(3) and install a -+enabled but set CURLOPT_REDIR_PROTOCOLS_STR(3) and install a - CURLOPT_OPENSOCKETFUNCTION(3) or CURLOPT_PREREQFUNCTION(3) callback - function in which addresses are sanitized before use. - -@@ -164,7 +165,7 @@ non-redirected URLs, if the user is allowed to specify an arbitrary URL that - could point to a private resource. For example, a web app providing a - translation service might happily translate **file://localhost/etc/passwd** - and display the result. Applications can mitigate against this with the --CURLOPT_PROTOCOLS(3) option as well as by similar mitigation techniques -+CURLOPT_PROTOCOLS_STR(3) option as well as by similar mitigation techniques - for redirections. - - A malicious FTP server could in response to the PASV command return an IP -@@ -308,9 +309,9 @@ Remedies: - - curl command lines can use *--proto* to limit what URL schemes it accepts - --## Use CURLOPT_PROTOCOLS -+## Use CURLOPT_PROTOCOLS_STR - --libcurl programs can use CURLOPT_PROTOCOLS(3) to limit what URL schemes it accepts -+libcurl programs can use CURLOPT_PROTOCOLS_STR(3) to limit what URL schemes it accepts - - ## consider not allowing the user to set the full URL - -@@ -380,10 +381,11 @@ CURLOPT_TIMEOUT(3) and/or CURLOPT_LOW_SPEED_LIMIT(3) options can - be used to mitigate against this. - - A malicious server could cause libcurl to download an infinite amount of data, --potentially causing all of memory or disk to be filled. Setting the --CURLOPT_MAXFILESIZE_LARGE(3) option is not sufficient to guard against --this. Instead, applications should monitor the amount of data received within --the write or progress callback and abort once the limit is reached. -+potentially causing system resources to be exhausted resulting in a system or -+application crash. Setting the CURLOPT_MAXFILESIZE_LARGE(3) option is not -+sufficient to guard against this. Instead, applications should monitor the -+amount of data received within the write or progress callback and abort once -+the limit is reached. - - A malicious HTTP server could cause an infinite redirection loop, causing a - denial-of-service. This can be mitigated by using the -@@ -458,7 +460,9 @@ created. - libcurl itself uses *fork()* and *execl()* if told to use the - **CURLAUTH_NTLM_WB** authentication method which then invokes the helper - command in a child process with file descriptors duplicated. Make sure that --only the trusted and reliable helper program is invoked! -+only the trusted and reliable helper program is invoked. -+ -+This feature was removed from curl in 8.8.0. - - # Secrets in memory - -diff --git a/docs/libcurl/libcurl-share.md b/docs/libcurl/libcurl-share.md -index f820967df..040059313 100644 ---- a/docs/libcurl/libcurl-share.md -+++ b/docs/libcurl/libcurl-share.md -@@ -13,6 +13,7 @@ See-also: - - libcurl-multi (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -35,7 +36,7 @@ The share interface was added to enable sharing of data between curl handles. - - You can have multiple easy handles share data between them. Have them update - and use the **same** cookie database, DNS cache, TLS session cache and/or --connection cache! This way, each single transfer takes advantage from data -+connection cache. This way, each single transfer takes advantage from data - updates made by the other transfer(s). - - # SHARE OBJECT -diff --git a/docs/libcurl/libcurl-thread.md b/docs/libcurl/libcurl-thread.md -index 4ca783af1..ef7ae9b7d 100644 ---- a/docs/libcurl/libcurl-thread.md -+++ b/docs/libcurl/libcurl-thread.md -@@ -8,6 +8,7 @@ See-also: - - libcurl-security (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -37,10 +38,28 @@ share API (the connection pool and HSTS cache for example). - - # TLS - --All current TLS libraries libcurl supports are thread-safe. OpenSSL 1.1.0+ can --be safely used in multi-threaded applications provided that support for the --underlying OS threading API is built-in. For older versions of OpenSSL, the --user must set mutex callbacks. -+All current TLS libraries libcurl supports are thread-safe. -+ -+## OpenSSL -+ -+OpenSSL 1.1.0+ can be safely used in multi-threaded applications provided that -+support for the underlying OS threading API is built-in. For older versions of -+OpenSSL, the user must set mutex callbacks. -+ -+libcurl may not be able to fully clean up after multi-threaded OpenSSL -+depending on how OpenSSL was built and loaded as a library. It is possible in -+some rare circumstances a memory leak could occur unless you implement your own -+OpenSSL thread cleanup. -+ -+For example, on Windows if both libcurl and OpenSSL are linked statically to a -+DLL or application then OpenSSL may leak memory unless the DLL or application -+calls OPENSSL_thread_stop() before each thread terminates. If OpenSSL is built -+as a DLL then it does this cleanup automatically and there is no leak. If -+libcurl is built as a DLL and OpenSSL is linked statically to it then libcurl -+does this cleanup automatically and there is no leak (added in libcurl 8.8.0). -+ -+Please review the OpenSSL documentation for a full list of circumstances: -+https://docs.openssl.org/3.0/man3/OPENSSL_init_crypto/#notes - - # Signals - -diff --git a/docs/libcurl/libcurl-tutorial.md b/docs/libcurl/libcurl-tutorial.md -index c51d9f13c..7c59e2f88 100644 ---- a/docs/libcurl/libcurl-tutorial.md -+++ b/docs/libcurl/libcurl-tutorial.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-url (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -111,7 +112,7 @@ specified are: - ## CURL_GLOBAL_WIN32 - - which only does anything on Windows machines. When used on a Windows machine, --it makes libcurl initialize the win32 socket stuff. Without having that -+it makes libcurl initialize the Win32 socket stuff. Without having that - initialized properly, your program cannot use sockets properly. You should - only do this once for each application, so if your program already does this - or of another library in use does it, you should not tell libcurl to do this -@@ -234,7 +235,7 @@ to make your program run fine virtually everywhere. - (CURLOPT_WRITEDATA(3) was formerly known as *CURLOPT_FILE*. Both names still - work and do the same thing). - --If you are using libcurl as a win32 DLL, you MUST use the -+If you are using libcurl as a Windows DLL, you MUST use the - CURLOPT_WRITEFUNCTION(3) if you set CURLOPT_WRITEDATA(3) - or experience - crashes. - -@@ -1254,7 +1255,7 @@ curl_mime_subparts(3). Once it has been - bound to its parent multi-part, a nth-level multi-part belongs to it and - should not be freed explicitly. - --Email messages data is not supposed to be non-ascii and line length is -+Email messages data is not supposed to be non-ASCII and line length is - limited: fortunately, some transfer encodings are defined by the standards to - support the transmission of such incompatible data. Function - curl_mime_encoder(3) tells a part that its source data must be encoded -diff --git a/docs/libcurl/libcurl-url.md b/docs/libcurl/libcurl-url.md -index e673873b4..82de7e782 100644 ---- a/docs/libcurl/libcurl-url.md -+++ b/docs/libcurl/libcurl-url.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: libcurl -+Title: libcurl-url - Section: 3 - Source: libcurl - See-also: -@@ -14,6 +14,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -103,7 +104,7 @@ Extracted parts are not URL decoded unless the user also asks for it with the - *CURLU_URLDECODE* flag set in the fourth bitmask argument. - - Remember to free the returned string with curl_free(3) when you are done --with it! -+with it. - - # SET PARTS - -@@ -156,9 +157,7 @@ Now the URL looks like - https://example.com/?shoes=2&hat=1&candy=N%26N - ~~~ - --# AVAILABILITY -- --The URL API was introduced in libcurl 7.62.0. -+# NOTES - - A URL with a literal IPv6 address can be parsed even when IPv6 support is not - enabled. -diff --git a/docs/libcurl/libcurl-ws.md b/docs/libcurl/libcurl-ws.md -index 25550ecd6..60c9fa59a 100644 ---- a/docs/libcurl/libcurl-ws.md -+++ b/docs/libcurl/libcurl-ws.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: libcurl -+Title: libcurl-ws - Section: 3 - Source: libcurl - See-also: -@@ -14,6 +14,7 @@ See-also: - - curl_ws_send (3) - Protocol: - - All -+Added-in: 7.86.0 - --- - - # NAME -@@ -115,7 +116,7 @@ Once such a setup has been successfully performed, the application can proceed - and use curl_ws_recv(3) and curl_ws_send(3) freely to exchange - WebSocket messages with the server. - --# AVAILABILITY -+# EXPERIMENTAL - - The WebSocket API was introduced as experimental in 7.86.0 and is still - experimental today. -diff --git a/docs/libcurl/libcurl.md b/docs/libcurl/libcurl.md -index 9031451cc..b6d4af36e 100644 ---- a/docs/libcurl/libcurl.md -+++ b/docs/libcurl/libcurl.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-thread (3) - Protocol: - - All -+Added-in: n/a - --- - - # NAME -@@ -94,7 +95,7 @@ See libcurl-ws(3) - - # LINKING WITH LIBCURL - --On unix-like machines, there is a tool named curl-config that gets installed -+On Unix-like machines, there is a tool named curl-config that gets installed - with the rest of the curl stuff when 'make install' is performed. - - curl-config is added to make it easier for applications to link with libcurl -@@ -118,7 +119,7 @@ a lowercase c). You can find other functions in the library source code, but - other prefixes indicate that the functions are private and may change without - further notice in the next release. - --Only use documented functions and functionality! -+Only use documented functions and functionality. - - # PORTABILITY - -diff --git a/docs/libcurl/mksymbolsmanpage.pl b/docs/libcurl/mksymbolsmanpage.pl -index fc9a8b704..c1a6b9d61 100755 ---- a/docs/libcurl/mksymbolsmanpage.pl -+++ b/docs/libcurl/mksymbolsmanpage.pl -@@ -48,6 +48,7 @@ See-also: - - libcurl-multi (3) - - libcurl-security (3) - - libcurl-thread (3) -+Added-in: n/a - --- - # libcurl symbols - -@@ -60,7 +61,7 @@ since that version no new code should be written to use the symbol as it is - marked for getting removed in a future. - - The last version that featured the specific symbol. Using the symbol in source --code will make it no longer compile error-free after that specified version. -+code makes it no longer compile error-free after that specified version. - - This man page is automatically generated from the symbols-in-versions file. - HEADER -diff --git a/docs/libcurl/opts/CMakeLists.txt b/docs/libcurl/opts/CMakeLists.txt -index a20d0b9bf..99683c406 100644 ---- a/docs/libcurl/opts/CMakeLists.txt -+++ b/docs/libcurl/opts/CMakeLists.txt -@@ -21,17 +21,17 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --# Load man_MANS from shared file -+# Get 'man_MANS' variable - transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - - add_manual_pages(man_MANS) --add_custom_target(opts-man DEPENDS ${man_MANS}) --add_dependencies(man opts-man) -+add_custom_target(curl-opts-man DEPENDS ${man_MANS}) -+add_dependencies(curl-man curl-opts-man) - if(NOT CURL_DISABLE_INSTALL) - unset(_src) -- foreach(_f ${man_MANS}) -+ foreach(_f IN LISTS man_MANS) - list(APPEND _src "${CMAKE_CURRENT_BINARY_DIR}/${_f}") - endforeach() -- install(FILES ${_src} DESTINATION ${CMAKE_INSTALL_MANDIR}/man3) -+ install(FILES ${_src} DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") - endif() -diff --git a/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md b/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md -index 92567e627..2b849afc5 100644 ---- a/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md -+++ b/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.45.0 - --- - - # NAME -@@ -40,6 +41,8 @@ CURLOPT_CONNECT_ONLY(3), which skips the transfer phase. - CURLINFO_ACTIVESOCKET(3) was added as a replacement for - CURLINFO_LASTSOCKET(3) since that one is not working on all platforms. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,21 +57,24 @@ int main(void) - /* Do not do the transfer - only connect to host */ - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); - res = curl_easy_perform(curl); -- -- /* Extract the socket from the curl handle */ -- res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); -- - if(res != CURLE_OK) { - printf("Error: %s\n", curl_easy_strerror(res)); -+ curl_easy_cleanup(curl); - return 1; - } -+ -+ /* Extract the socket from the curl handle */ -+ res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd); -+ if(!res && sockfd != CURL_SOCKET_BAD) { -+ /* operate on sockfd */ -+ } -+ -+ curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.45.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md -index a40f6d02e..61ea7ba8b 100644 ---- a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.19.0 - --- - - # NAME -@@ -29,14 +30,16 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_APPCONNECT_TIME, - - Pass a pointer to a double to receive the time, in seconds, it took from the - start until the SSL/SSH connect/handshake to the remote host was completed. --This time is most often close to the CURLINFO_PRETRANSFER_TIME(3) time, --except for cases such as HTTP pipelining where the pretransfer time can be --delayed due to waits in line for the pipeline and more. -+This time is most often close to the CURLINFO_PRETRANSFER_TIME(3) time, except -+for cases such as HTTP multiplexing where the pretransfer time can be delayed -+due to waits in line for the stream and more. - - When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md -index 0d61f05d2..4490fd032 100644 ---- a/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -29,15 +30,16 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_APPCONNECT_TIME_T, - - Pass a pointer to a curl_off_t to receive the time, in microseconds, it took - from the start until the SSL/SSH connect/handshake to the remote host was --completed. This time is most often close to the --CURLINFO_PRETRANSFER_TIME_T(3) time, except for cases such as HTTP --pipelining where the pretransfer time can be delayed due to waits in line for --the pipeline and more. -+completed. This time is most often close to the CURLINFO_PRETRANSFER_TIME_T(3) -+time, except for cases such as HTTP multiplexing where the pretransfer time -+can be delayed due to waits in line for the stream and more. - - When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CAINFO.md b/docs/libcurl/opts/CURLINFO_CAINFO.md -index ea61a1a74..60c131d9e 100644 ---- a/docs/libcurl/opts/CURLINFO_CAINFO.md -+++ b/docs/libcurl/opts/CURLINFO_CAINFO.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.84.0 - --- - - # NAME -@@ -40,6 +41,8 @@ This is a path identifying a single file containing CA certificates. - - The **path** pointer is set to NULL if there is no default path. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.84.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CAPATH.md b/docs/libcurl/opts/CURLINFO_CAPATH.md -index 8b6f8bf77..6211859a5 100644 ---- a/docs/libcurl/opts/CURLINFO_CAPATH.md -+++ b/docs/libcurl/opts/CURLINFO_CAPATH.md -@@ -15,6 +15,7 @@ TLS-backend: - - GnuTLS - - mbedTLS - - wolfSSL -+Added-in: 7.84.0 - --- - - # NAME -@@ -43,6 +44,8 @@ This is a path identifying a directory. - - The **path** pointer is set to NULL if there is no default path. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.84.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CERTINFO.md b/docs/libcurl/opts/CURLINFO_CERTINFO.md -index 633beed17..e73b2aee7 100644 ---- a/docs/libcurl/opts/CURLINFO_CERTINFO.md -+++ b/docs/libcurl/opts/CURLINFO_CERTINFO.md -@@ -15,6 +15,7 @@ TLS-backend: - - GnuTLS - - Schannel - - Secure Transport -+Added-in: 7.19.1 - --- - - # NAME -@@ -50,6 +51,8 @@ items with textual information in the format "name:content" such as - "Subject:Foo", "Issuer:Bar", etc. The items in each list varies depending on - the SSL backend and the certificate. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -91,13 +94,12 @@ int main(void) - - See also the *certinfo.c* example. - --# AVAILABILITY -+# HISTORY - --This option is only working in libcurl built with OpenSSL, GnuTLS, Schannel or --Secure Transport. GnuTLS support added in 7.42.0. Schannel support added in --7.50.0. Secure Transport support added in 7.79.0. -+GnuTLS support added in 7.42.0. Schannel support added in 7.50.0. Secure -+Transport support added in 7.79.0. mbedTLS support added in 8.9.0. - --Added in 7.19.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md b/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md -index 00cbd5308..6befaf8a0 100644 ---- a/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md -+++ b/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.19.4 - --- - - # NAME -@@ -36,6 +37,8 @@ gets a zero stored if the condition instead was met. This can also return 1 if - the server responded with a 304 HTTP status code, for example after sending a - custom "If-Match-*" header. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md b/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md -index 7a5b4bdfc..dbf1a56fc 100644 ---- a/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -33,6 +34,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md -index 00d582388..073a93b9c 100644 ---- a/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -35,6 +36,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONN_ID.md b/docs/libcurl/opts/CURLINFO_CONN_ID.md -index 3face4207..41a3b16fc 100644 ---- a/docs/libcurl/opts/CURLINFO_CONN_ID.md -+++ b/docs/libcurl/opts/CURLINFO_CONN_ID.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 8.2.0 - --- - - # NAME -@@ -34,6 +35,8 @@ The connection id is unique among all connections using the same - connection cache. This is implicitly the case for all connections in the - same multi handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 8.2.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md -index 0cb1b47d1..77b7be406 100644 ---- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.6.1 - --- - - # NAME -@@ -34,6 +35,8 @@ is the value read from the Content-Length: field. Since 7.19.4, this returns - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more - sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.6.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md -index 15b4f631f..ea08eb931 100644 ---- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.55.0 - --- - - # NAME -@@ -31,6 +32,8 @@ Pass a pointer to a *curl_off_t* to receive the content-length of the - download. This is the value read from the Content-Length: field. Stores -1 if - the size is not known. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md -index 7cba9aa33..322a84a56 100644 ---- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.6.1 - --- - - # NAME -@@ -33,6 +34,8 @@ Pass a pointer to a double to receive the specified size of the upload. Since - CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) is a newer replacement that returns a - more sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.6.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md -index babd796e3..4f018711a 100644 ---- a/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -30,6 +31,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_UPLOAD_T, - Pass a pointer to a *curl_off_t* to receive the specified size of the - upload. Stores -1 if the size is not known. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md -index 25cb737e0..9e1800f8d 100644 ---- a/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md -+++ b/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.9.4 - --- - - # NAME -@@ -39,6 +40,8 @@ corresponding CURL handle. - The modern way to get this header from a response is to instead use the - curl_easy_header(3) function. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_COOKIELIST.md b/docs/libcurl/opts/CURLINFO_COOKIELIST.md -index 64e9f4a65..0481c1277 100644 ---- a/docs/libcurl/opts/CURLINFO_COOKIELIST.md -+++ b/docs/libcurl/opts/CURLINFO_COOKIELIST.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.14.1 - --- - - # NAME -@@ -36,6 +37,8 @@ received) the 'struct curl_slist *' is made a NULL pointer. - Since 7.43.0 cookies that were imported in the Set-Cookie format without a - domain name are not exported by this option. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.14.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_EARLYDATA_SENT_T.md b/docs/libcurl/opts/CURLINFO_EARLYDATA_SENT_T.md -new file mode 100644 -index 000000000..427746077 ---- /dev/null -+++ b/docs/libcurl/opts/CURLINFO_EARLYDATA_SENT_T.md -@@ -0,0 +1,75 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Title: CURLINFO_EARLYDATA_SENT_T -+Section: 3 -+Source: libcurl -+See-also: -+ - curl_easy_getinfo (3) -+ - curl_easy_setopt (3) -+Protocol: -+ - TLS -+TLS-backend: -+ - GnuTLS -+Added-in: 8.11.0 -+--- -+ -+# NAME -+ -+CURLINFO_EARLYDATA_SENT_T - get the number of bytes sent as TLS early data -+ -+# SYNOPSIS -+ -+~~~c -+#include -+ -+CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_EARLYDATA_SENT_T, -+ curl_off_t *amount); -+~~~ -+ -+# DESCRIPTION -+ -+Pass a pointer to an *curl_off_t* to receive the total amount of bytes that -+were sent to the server as TLSv1.3 early data. When no TLS early -+data is used, this reports 0. -+ -+TLS early data is only attempted when CURLSSLOPT_EARLYDATA is set for the -+transfer. In addition, it is only used by libcurl when a TLS session exists -+that announces support. -+ -+The amount is **negative** when the sent data was rejected -+by the server. TLS allows a server that announces support for early data to -+reject any attempt to use it at its own discretion. When for example 127 -+bytes had been sent, but were rejected, it reports -127 as the amount "sent". -+ -+# %PROTOCOLS% -+ -+# EXAMPLE -+ -+~~~c -+int main(void) -+{ -+ CURL *curl = curl_easy_init(); -+ if(curl) { -+ CURLcode res; -+ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); -+ -+ /* Perform the request */ -+ res = curl_easy_perform(curl); -+ -+ if(!res) { -+ curl_off_t amount; -+ res = curl_easy_getinfo(curl, CURLINFO_EARLYDATA_SENT_T, &amount); -+ if(!res) { -+ printf("TLS earlydata: %" CURL_FORMAT_CURL_OFF_T " bytes\n", amount); -+ } -+ } -+ } -+} -+~~~ -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md -index e10142f5d..86080c579 100644 ---- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md -+++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.72.0 - --- - - # NAME -@@ -38,6 +39,8 @@ The **methodp** pointer is NULL or points to private memory. You MUST NOT - free - it gets freed when you call curl_easy_cleanup(3) on the - corresponding CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.72.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md -index 3892bd7bc..c1f395227 100644 ---- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md -+++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.4 - --- - - # NAME -@@ -35,6 +36,8 @@ The **urlp** pointer is NULL or points to private memory. You MUST NOT free - - it gets freed when you call curl_easy_cleanup(3) on the corresponding - CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_FILETIME.md b/docs/libcurl/opts/CURLINFO_FILETIME.md -index 4e4d7f190..40482e36f 100644 ---- a/docs/libcurl/opts/CURLINFO_FILETIME.md -+++ b/docs/libcurl/opts/CURLINFO_FILETIME.md -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - FTP - - SFTP -+Added-in: 7.5 - --- - - # NAME -@@ -34,12 +35,13 @@ in number of seconds since January 1 1970 in the GMT/UTC time zone. If you get - hide it or the server does not support the command that tells document time - etc) and the time of the document is unknown. - --You must tell libcurl to collect this information before the transfer is made, --by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or --you this unconditionally gets a -1 back. -+You must ask libcurl to collect this information before the transfer is made, -+by using the CURLOPT_FILETIME(3) option or you unconditionally get a -1 back. - --Consider using CURLINFO_FILETIME_T(3) to be able to extract dates beyond --the year 2038 on systems using 32 bit longs (Windows). -+Consider CURLINFO_FILETIME_T(3) instead to be able to extract dates beyond the -+year 2038 on systems using 32-bit longs (Windows). -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -67,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_FILETIME_T.md b/docs/libcurl/opts/CURLINFO_FILETIME_T.md -index 0ba24d61f..7cdec9b4c 100644 ---- a/docs/libcurl/opts/CURLINFO_FILETIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_FILETIME_T.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: CURLINFO_FILETIME -+Title: CURLINFO_FILETIME_T - Section: 3 - Source: libcurl - See-also: -@@ -12,6 +12,7 @@ Protocol: - - HTTP - - FTP - - SFTP -+Added-in: 7.59.0 - --- - - # NAME -@@ -30,18 +31,18 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME_T, - # DESCRIPTION - - Pass a pointer to a curl_off_t to receive the remote time of the retrieved --document in number of seconds since January 1 1970 in the GMT/UTC time --zone. If you get -1, it can be because of many reasons (it might be unknown, --the server might hide it or the server does not support the command that tells -+document in number of seconds since January 1 1970 in the GMT/UTC time zone. -+If you get -1, it can be because of many reasons (it might be unknown, the -+server might hide it or the server does not support the command that tells - document time etc) and the time of the document is unknown. - - You must ask libcurl to collect this information before the transfer is made, --by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or --you unconditionally get a -1 back. -+by using the CURLOPT_FILETIME(3) option or you unconditionally get a -1 back. - --This option is an alternative to CURLINFO_FILETIME(3) to allow systems --with 32 bit long variables to extract dates outside of the 32bit timestamp --range. -+This option is an alternative to CURLINFO_FILETIME(3) to allow systems with 32 -+bit long variables to extract dates outside of the 32-bit timestamp range. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -69,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.59.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md -index 2276a5513..245a84936 100644 ---- a/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md -+++ b/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - FTP -+Added-in: 7.15.4 - --- - - # NAME -@@ -34,6 +35,8 @@ The **path** pointer is NULL or points to private memory. You MUST NOT free - - it gets freed when you call curl_easy_cleanup(3) on the corresponding - CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Works for SFTP since 7.21.4 - --Added in 7.15.4. Works for SFTP since 7.21.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md b/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md -index f60ab5245..ce8764c96 100644 ---- a/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md -+++ b/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -33,6 +34,8 @@ received. Measured in number of bytes. - The total includes the size of any received headers suppressed by - CURLOPT_SUPPRESS_CONNECT_HEADERS(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md b/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md -index 21d92c323..b0b229eb3 100644 ---- a/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md -+++ b/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.10.8 - --- - - # NAME -@@ -29,8 +30,9 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTPAUTH_AVAIL, long *authp); - - Pass a pointer to a long to receive a bitmask indicating the authentication - method(s) available according to the previous response. The meaning of the --bits is explained in the CURLOPT_HTTPAUTH(3) option for --curl_easy_setopt(3). -+bits is explained in the CURLOPT_HTTPAUTH(3) option for curl_easy_setopt(3). -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -65,10 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added RFC 2617 in 7.10.8 --Added RFC 7616 in 7.57.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md b/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md -index d5fb41c3d..b93f9d6f5 100644 ---- a/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md -+++ b/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.10.7 - --- - - # NAME -@@ -30,6 +31,8 @@ Pass a pointer to a long to receive the last received HTTP proxy response code - to a CONNECT request. The returned value is zero if no such response code was - available. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md b/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md -index 8ca341fe2..2721eb3fc 100644 ---- a/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md -+++ b/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.50.0 - --- - - # NAME -@@ -31,6 +32,8 @@ connection done using this handle. The returned value is - CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_2_0, - CURL_HTTP_VERSION_3 or 0 if the version cannot be determined. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.50.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_LASTSOCKET.md b/docs/libcurl/opts/CURLINFO_LASTSOCKET.md -index 8e98df90e..957f21f4b 100644 ---- a/docs/libcurl/opts/CURLINFO_LASTSOCKET.md -+++ b/docs/libcurl/opts/CURLINFO_LASTSOCKET.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.15.2 - --- - - # NAME -@@ -40,6 +41,8 @@ NOTE: this API is deprecated since it is not working on win64 where the SOCKET - type is 64 bits large while its 'long' is 32 bits. Use the - CURLINFO_ACTIVESOCKET(3) instead, if possible. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -48,27 +51,30 @@ int main(void) - CURL *curl = curl_easy_init(); - if(curl) { - CURLcode res; -- long sockfd; /* does not work on win64! */ -+ long sockfd; /* does not work on win64 */ - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); - - /* Do not do the transfer - only connect to host */ - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); - res = curl_easy_perform(curl); -- -- /* Extract the socket from the curl handle */ -- res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd); -- - if(res != CURLE_OK) { - printf("Error: %s\n", curl_easy_strerror(res)); -+ curl_easy_cleanup(curl); - return 1; - } -+ -+ /* Extract the socket from the curl handle */ -+ res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockfd); -+ if(!res && sockfd != -1) { -+ /* operate on sockfd */ -+ } -+ -+ curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md -index d3e2118b1..f8470b048 100644 ---- a/docs/libcurl/opts/CURLINFO_LOCAL_IP.md -+++ b/docs/libcurl/opts/CURLINFO_LOCAL_IP.md -@@ -10,7 +10,9 @@ See-also: - - curl_easy_getinfo (3) - - curl_easy_setopt (3) - Protocol: -- - All -+ - TCP -+ - QUIC -+Added-in: 7.21.0 - --- - - # NAME -@@ -29,13 +31,15 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_IP, char **ip); - - Pass a pointer to a char pointer to receive the pointer to a null-terminated - string holding the IP address of the local end of most recent connection done --with this **curl** handle. This string may be IPv6 when that is --enabled. Note that you get a pointer to a memory area that is reused at next --request so you need to copy the string if you want to keep the information. -+with this **curl** handle. This string may be IPv6 when that is enabled. Note -+that you get a pointer to a memory area that is reused at next request so you -+need to copy the string if you want to keep the information. - --The **ip** pointer is NULL or points to private memory. You MUST NOT free - --it gets freed when you call curl_easy_cleanup(3) on the corresponding --CURL handle. -+The **ip** pointer is NULL or points to private memory. You MUST NOT free - it -+gets freed when you call curl_easy_cleanup(3) on the corresponding CURL -+handle. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -61,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md b/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md -index 470341600..a73496be3 100644 ---- a/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md -+++ b/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md -@@ -6,11 +6,13 @@ Section: 3 - Source: libcurl - Protocol: - - TCP -+ - QUIC - See-also: - - CURLINFO_LOCAL_IP (3) - - CURLINFO_PRIMARY_PORT (3) - - curl_easy_getinfo (3) - - curl_easy_setopt (3) -+Added-in: 7.21.0 - --- - - # NAME -@@ -30,6 +32,11 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_PORT, long *portp); - Pass a pointer to a long to receive the local port number of the most recent - connection done with this **curl** handle. - -+If the connection was done using QUIC, the port number is a UDP port number, -+otherwise it is a TCP port number. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md -index 29dd375a5..349e300e8 100644 ---- a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -34,6 +35,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md -index eb0bae797..d263eb612 100644 ---- a/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -34,6 +35,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md b/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md -index 5488fcc42..1a0a83f8f 100644 ---- a/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md -+++ b/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.12.3 - --- - - # NAME -@@ -32,6 +33,8 @@ many times libcurl successfully reused existing connection(s) or not. See the - connection options of curl_easy_setopt(3) to see how libcurl tries to make - persistent connections to save time. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -46,7 +49,7 @@ int main(void) - if(res == CURLE_OK) { - long connects; - res = curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &connects); -- if(res) -+ if(!res) - printf("It needed %ld connects\n", connects); - } - curl_easy_cleanup(curl); -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.12.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_OS_ERRNO.md b/docs/libcurl/opts/CURLINFO_OS_ERRNO.md -index 85084778a..969f1a36c 100644 ---- a/docs/libcurl/opts/CURLINFO_OS_ERRNO.md -+++ b/docs/libcurl/opts/CURLINFO_OS_ERRNO.md -@@ -9,6 +9,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.12.2 - --- - - # NAME -@@ -29,6 +30,16 @@ Pass a pointer to a long to receive the errno variable from a connect failure. - Note that the value is only set on failure, it is not reset upon a successful - operation. The number is OS and system specific. - -+libcurl network-related errors that may have a saved errno are: -+CURLE_COULDNT_CONNECT, CURLE_FAILED_INIT, CURLE_INTERFACE_FAILED, -+CURLE_OPERATION_TIMEDOUT, CURLE_RECV_ERROR, CURLE_SEND_ERROR. -+ -+Since 8.8.0 libcurl clears the easy handle's saved errno before performing the -+transfer. Prior versions did not clear the saved errno, which means if a saved -+errno is retrieved it could be from a previous transfer on the same handle. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -42,7 +53,7 @@ int main(void) - if(res != CURLE_OK) { - long error; - res = curl_easy_getinfo(curl, CURLINFO_OS_ERRNO, &error); -- if(res && error) { -+ if(!res && error) { - printf("Errno: %ld\n", error); - } - } -@@ -51,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.12.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_POSTTRANSFER_TIME_T.md b/docs/libcurl/opts/CURLINFO_POSTTRANSFER_TIME_T.md -new file mode 100644 -index 000000000..9acdbd7fb ---- /dev/null -+++ b/docs/libcurl/opts/CURLINFO_POSTTRANSFER_TIME_T.md -@@ -0,0 +1,70 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Title: CURLINFO_POSTTRANSFER_TIME_T -+Section: 3 -+Source: libcurl -+See-also: -+ - CURLINFO_PRETRANSFER_TIME_T (3) -+ - CURLOPT_TIMEOUT (3) -+ - curl_easy_getinfo (3) -+ - curl_easy_setopt (3) -+Protocol: -+ - All -+Added-in: 8.10.0 -+--- -+ -+# NAME -+ -+CURLINFO_POSTTRANSFER_TIME_T - get the time until the last byte is sent -+ -+# SYNOPSIS -+ -+~~~c -+#include -+ -+CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_POSTTRANSFER_TIME_T, -+ curl_off_t *timep); -+~~~ -+ -+# DESCRIPTION -+ -+Pass a pointer to a curl_off_t to receive the time, in microseconds, -+it took from the start until the last byte is sent by libcurl. -+ -+When a redirect is followed, the time from each request is added together. -+ -+See also the TIMES overview in the curl_easy_getinfo(3) man page. -+ -+# %PROTOCOLS% -+ -+# EXAMPLE -+ -+~~~c -+int main(void) -+{ -+ CURL *curl = curl_easy_init(); -+ if(curl) { -+ CURLcode res; -+ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); -+ res = curl_easy_perform(curl); -+ if(CURLE_OK == res) { -+ curl_off_t posttransfer; -+ res = curl_easy_getinfo(curl, CURLINFO_POSTTRANSFER_TIME_T, -+ &posttransfer); -+ if(CURLE_OK == res) { -+ printf("Request sent after: %" CURL_FORMAT_CURL_OFF_T ".%06ld us", -+ posttransfer / 1000000, (long)(posttransfer % 1000000)); -+ } -+ } -+ /* always cleanup */ -+ curl_easy_cleanup(curl); -+ } -+} -+~~~ -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md -index 04adf5aa6..0d3e3304d 100644 ---- a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -39,6 +40,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md -index b1049a663..0300312de 100644 ---- a/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -39,6 +40,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md -index 31237f656..83f431fd8 100644 ---- a/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md -+++ b/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.19.0 - --- - - # NAME -@@ -38,6 +39,8 @@ The **ip** pointer is NULL or points to private memory. You MUST NOT free - - it gets freed when you call curl_easy_cleanup(3) on the corresponding - CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md b/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md -index a1de51db3..d44594e33 100644 ---- a/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md -+++ b/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.21.0 - --- - - # NAME -@@ -35,6 +36,8 @@ If a proxy was used for the most recent transfer, this is the port number of - the proxy, if no proxy was used it is the port number of the most recently - accessed URL. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PRIVATE.md b/docs/libcurl/opts/CURLINFO_PRIVATE.md -index 4a4d35150..0ce649924 100644 ---- a/docs/libcurl/opts/CURLINFO_PRIVATE.md -+++ b/docs/libcurl/opts/CURLINFO_PRIVATE.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -31,6 +32,8 @@ associated with the curl handle (set with the CURLOPT_PRIVATE(3)). - Please note that for internal reasons, the value is returned as a char - pointer, although effectively being a 'void *'. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PROTOCOL.md b/docs/libcurl/opts/CURLINFO_PROTOCOL.md -index 13c597381..6e466f777 100644 ---- a/docs/libcurl/opts/CURLINFO_PROTOCOL.md -+++ b/docs/libcurl/opts/CURLINFO_PROTOCOL.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -28,7 +29,7 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROTOCOL, long *p); - - This option is deprecated. We strongly recommend using - CURLINFO_SCHEME(3) instead, because this option cannot return all --possible protocols! -+possible protocols. - - Pass a pointer to a long to receive the version used in the last http - connection. The returned value is set to one of the CURLPROTO_* values: -@@ -43,6 +44,8 @@ CURLPROTO_SCP, CURLPROTO_SFTP, CURLPROTO_SMB, CURLPROTO_SMBS, CURLPROTO_SMTP, - CURLPROTO_SMTPS, CURLPROTO_TELNET, CURLPROTO_TFTP, CURLPROTO_MQTT - ~~~ - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.85.0. - --Added in 7.52.0. Deprecated since 7.85.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md b/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md -index 823bdd385..201c0d996 100644 ---- a/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md -+++ b/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.10.8 - --- - - # NAME -@@ -29,8 +30,9 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXYAUTH_AVAIL, - - Pass a pointer to a long to receive a bitmask indicating the authentication - method(s) available according to the previous response. The meaning of the --bits is explained in the CURLOPT_PROXYAUTH(3) option for --curl_easy_setopt(3). -+bits is explained in the CURLOPT_PROXYAUTH(3) option for curl_easy_setopt(3). -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -66,10 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added RFC 2617 in 7.10.8 --Added RFC 7616 in 7.57.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md -index 1d8855f37..52572b99b 100644 ---- a/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md -+++ b/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md -@@ -11,6 +11,7 @@ See-also: - - libcurl-errors (3) - Protocol: - - All -+Added-in: 7.73.0 - --- - - # NAME -@@ -71,6 +72,8 @@ transfer returned a **CURLE_PROXY** error. That error code matches the - - The error code is zero (**CURLPX_OK**) if no response code was available. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -94,9 +97,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.73.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md -index 073de0aa5..f1aeb052c 100644 ---- a/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md -+++ b/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.52.0 - --- - - # NAME -@@ -34,6 +35,10 @@ Pass a pointer to a long to receive the result of the certificate verification - that was requested (using the CURLOPT_PROXY_SSL_VERIFYPEER(3) - option. This is only used for HTTPS proxies. - -+0 is a positive result. Non-zero is an error. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -43,22 +48,29 @@ int main(void) - if(curl) { - CURLcode res; - long verifyresult; -+ - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); - curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443"); -+ - res = curl_easy_perform(curl); -- if(res) -+ if(res) { - printf("error: %s\n", curl_easy_strerror(res)); -- curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, &verifyresult); -- printf("The peer verification said %s\n", verifyresult? -- "fine" : "bad"); -+ curl_easy_cleanup(curl); -+ return 1; -+ } -+ -+ res = curl_easy_getinfo(curl, CURLINFO_PROXY_SSL_VERIFYRESULT, -+ &verifyresult); -+ if(!res) { -+ printf("The peer verification said %s\n", -+ (verifyresult ? "bad" : "fine")); -+ } - curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md b/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md -index c61ca2faa..c066e4ca5 100644 ---- a/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 8.6.0 - --- - - # NAME -@@ -35,6 +36,8 @@ connection etc due to set conditions and limits imposed by the application. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 8.6.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md b/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md -index bcfaa362d..c5999247e 100644 ---- a/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md -+++ b/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.9.7 - --- - - # NAME -@@ -31,6 +32,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_COUNT, - Pass a pointer to a long to receive the total number of redirections that were - actually followed. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md -index 202343d61..f60b5e541 100644 ---- a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.9.7 - --- - - # NAME -@@ -36,6 +37,8 @@ the complete execution time for multiple redirections. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md -index 0ccafa077..1c69bfcf1 100644 ---- a/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.61.0 - --- - - # NAME -@@ -37,6 +38,8 @@ multiple redirections. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md b/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md -index 70a4f6cc3..9926a5edb 100644 ---- a/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md -+++ b/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.18.2 - --- - - # NAME -@@ -28,14 +29,16 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_URL, char **urlp); - - # DESCRIPTION - --Pass a pointer to a char pointer to receive the URL a redirect *would* --take you to if you would enable CURLOPT_FOLLOWLOCATION(3). This can come --handy if you think using the built-in libcurl redirect logic is not good enough --for you but you would still prefer to avoid implementing all the magic of --figuring out the new URL. -+Pass a pointer to a char pointer to receive the URL a redirect *would* take -+you to if you would enable CURLOPT_FOLLOWLOCATION(3). This can come handy if -+you think using the built-in libcurl redirect logic is not good enough for you -+but you would still prefer to avoid implementing all the magic of figuring out -+the new URL. - --This URL is also set if the CURLOPT_MAXREDIRS(3) limit prevented a --redirect to happen (since 7.54.1). -+This URL is also set if the CURLOPT_MAXREDIRS(3) limit prevented a redirect to -+happen (since 7.54.1). -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REFERER.md b/docs/libcurl/opts/CURLINFO_REFERER.md -index 6850b6de7..b74a7016b 100644 ---- a/docs/libcurl/opts/CURLINFO_REFERER.md -+++ b/docs/libcurl/opts/CURLINFO_REFERER.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - HTTP -+Added-in: 7.76.0 - --- - - # NAME -@@ -34,6 +35,8 @@ The **hdrp** pointer is NULL or points to private memory you MUST NOT free - - it gets freed when you call curl_easy_cleanup(3) on the corresponding - CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.76.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md b/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md -index 89452d32b..3b0c66dc9 100644 ---- a/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md -+++ b/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -31,6 +32,8 @@ Pass a pointer to a long to receive the total size of the issued - requests. This is so far only for HTTP requests. Note that this may be more - than one request if CURLOPT_FOLLOWLOCATION(3) is enabled. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -52,9 +55,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md -index ea7d8f3f4..05e88387c 100644 ---- a/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md -+++ b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md -@@ -13,6 +13,7 @@ Protocol: - - FTP - - SMTP - - LDAP -+Added-in: 7.10.8 - --- - - # NAME -@@ -37,6 +38,8 @@ no server response code has been received. - Note that a proxy's CONNECT response should be read with - CURLINFO_HTTP_CONNECTCODE(3) and not this. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,10 +59,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES -+ -+The former name, CURLINFO_HTTP_CODE, was added in 7.4.1. Support for SMTP -+responses added in 7.25.0, for OpenLDAP in 7.81.0. - --Added in 7.10.8. CURLINFO_HTTP_CODE was added in 7.4.1. --Support for SMTP responses added in 7.25.0, for OpenLDAP in 7.81.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md b/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md -index b194fc922..0dca2e509 100644 ---- a/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md -+++ b/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_header (3) - Protocol: - - All -+Added-in: 7.66.0 - --- - - # NAME -@@ -37,7 +38,9 @@ or zero if there was no header or the header could not be parsed. - - # DEFAULT - --Returns zero delay if there was no header. -+Zero if there was no header. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.66.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md b/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md -index d79e2cc70..52640e998 100644 ---- a/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md -+++ b/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -31,6 +32,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_CLIENT_CSEQ, - Pass a pointer to a long to receive the next CSeq that is expected to be used - by the application. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md b/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md -index 3e9d17fcc..4eb11b411 100644 ---- a/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md -+++ b/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -31,6 +32,8 @@ server. If your application encounters a *CURLE_RTSP_CSEQ_ERROR* then you - may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this - value. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md b/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md -index 5b866c571..ee306e8e6 100644 ---- a/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md -+++ b/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -30,11 +31,13 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_SERVER_CSEQ, - Pass a pointer to a long to receive the next CSeq that is expected to be used - by the application. - --Listening for server initiated requests is not implemented! -+Listening for server initiated requests is not implemented. - - Applications wishing to resume an RTSP session on another connection should - retrieve this info before closing the active connection. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md -index 24a2b1d57..04feb1b6b 100644 ---- a/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md -+++ b/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -36,6 +37,8 @@ The **id** pointer is NULL or points to private memory. You MUST NOT free - - it gets freed when you call curl_easy_cleanup(3) on the corresponding - CURL handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SCHEME.md b/docs/libcurl/opts/CURLINFO_SCHEME.md -index 5b89bfc14..8c109839e 100644 ---- a/docs/libcurl/opts/CURLINFO_SCHEME.md -+++ b/docs/libcurl/opts/CURLINFO_SCHEME.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -33,8 +34,13 @@ string holding the URL scheme used for the most recent connection done with - this CURL **handle**. - - The **scheme** pointer is NULL or points to private memory. You MUST NOT --free - it gets freed when you call curl_easy_cleanup(3) on the --corresponding CURL handle. -+free - it gets freed when you call curl_easy_cleanup(3) on the corresponding -+CURL handle. -+ -+The returned scheme might be upper or lowercase. Do comparisons case -+insensitively. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -57,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md -index 6eaad7b7c..9c9866496 100644 ---- a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -37,6 +38,8 @@ number. - CURLINFO_SIZE_DOWNLOAD_T(3) is a newer replacement that returns a more - sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.4.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md -index 9c2a9cea6..e886f2c11 100644 ---- a/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md -@@ -12,6 +12,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -34,6 +35,8 @@ were downloaded. The amount is only for the latest transfer and gets reset - again for each new transfer. This counts actual payload data, what's also - commonly called body. All meta and header data is excluded from this amount. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md -index fa3989eed..1ecbddbea 100644 ---- a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -34,6 +35,8 @@ uploaded. - CURLINFO_SIZE_UPLOAD_T(3) is a newer replacement that returns a more - sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.4.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md -index bea4078ca..06ee47dab 100644 ---- a/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -31,6 +32,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD_T, - Pass a pointer to a *curl_off_t* to receive the total amount of bytes that - were uploaded. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md -index 98ada9adf..52e7cd0cb 100644 ---- a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -34,6 +35,8 @@ measured for the complete download. Measured in bytes/second. - CURLINFO_SPEED_DOWNLOAD_T(3) is a newer replacement that returns a more - sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.4.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md -index a1f8178bd..a42356b36 100644 ---- a/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -31,6 +32,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_DOWNLOAD_T, - Pass a pointer to a *curl_off_t* to receive the average download speed - that curl measured for the complete download. Measured in bytes/second. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md -index f963eca19..15d8cf23c 100644 ---- a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md -+++ b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -32,6 +33,8 @@ measured for the complete upload. Measured in bytes/second. - CURLINFO_SPEED_UPLOAD_T(3) is a newer replacement that returns a more - sensible variable type. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.55.0. - --Added in 7.4.1. Deprecated since 7.55.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md -index 45cb6bf2d..446943433 100644 ---- a/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md -+++ b/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -30,6 +31,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_UPLOAD_T, - Pass a pointer to a *curl_off_t* to receive the average upload speed that - curl measured for the complete upload. Measured in bytes/second. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md b/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md -index 9a4108734..553bd039b 100644 ---- a/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md -+++ b/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.12.3 - --- - - # NAME -@@ -36,6 +37,8 @@ available at runtime. **NOTE:** you must call curl_slist_free_all(3) - on the list pointer once you are done with it, as libcurl does not free this - data for you. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.12.3. Available in OpenSSL builds with "engine" support. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md -index 27cbfde71..69726b352 100644 ---- a/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md -+++ b/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.5 - --- - - # NAME -@@ -36,6 +37,8 @@ option). - - 0 is a positive result. Non-zero is an error. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -45,21 +48,28 @@ int main(void) - if(curl) { - CURLcode res; - long verifyresult; -+ - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); -+ - res = curl_easy_perform(curl); -- if(res) -+ if(res) { - printf("error: %s\n", curl_easy_strerror(res)); -- curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, &verifyresult); -- printf("The peer verification said %s\n", verifyresult? -- "BAAAD":"fine"); -+ curl_easy_cleanup(curl); -+ return 1; -+ } -+ -+ res = curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, -+ &verifyresult); -+ if(!res) { -+ printf("The peer verification said %s\n", -+ (verifyresult ? "bad" : "fine")); -+ } - curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.5. Only set by the OpenSSL/libressl/boringssl and GnuTLS backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md -index b58e41ac5..0e64ba8bf 100644 ---- a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.9.2 - --- - - # NAME -@@ -37,6 +38,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.9.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md -index 27c55bfc8..39894d6f7 100644 ---- a/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -38,6 +39,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md -index 2dc710a4a..e990ec6ec 100644 ---- a/docs/libcurl/opts/CURLINFO_TLS_SESSION.md -+++ b/docs/libcurl/opts/CURLINFO_TLS_SESSION.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.34.0 - --- - - # NAME -@@ -47,6 +48,8 @@ function *SSL_get_SSL_CTX(3)*. Therefore unless you need compatibility - with older versions of libcurl use CURLINFO_TLS_SSL_PTR(3). Refer to - that document for more information. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,10 +69,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.48.0 - --Added in 7.34.0. Deprecated since 7.48.0 and supported by OpenSSL and GnuTLS --only up until this version was released. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md b/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md -index 097bf98b3..de8965a19 100644 ---- a/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md -+++ b/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md -@@ -18,6 +18,7 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -+Added-in: 7.48.0 - --- - - # NAME -@@ -60,8 +61,8 @@ struct curl_tlssessioninfo { - The *backend* struct member is one of the defines in the CURLSSLBACKEND_* - series: CURLSSLBACKEND_NONE (when built without TLS support), - CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS, --CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL, --CURLSSLBACKEND_SCHANNEL or CURLSSLBACKEND_MESALINK. (Note that the OpenSSL -+CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL or -+CURLSSLBACKEND_SCHANNEL. (Note that the OpenSSL - forks are all reported as just OpenSSL here.) - - The *internals* struct member points to a TLS library specific pointer for -@@ -95,6 +96,8 @@ as well: - - **SSL *** - -+## -+ - If the *internals* pointer is NULL then either the SSL backend is not - supported, an SSL session has not yet been established or the connection is no - longer associated with the easy handle (e.g. curl_easy_perform(3) has -@@ -131,6 +134,8 @@ How are you using this option? Are you affected by any of these limitations? - Please let us know by making a comment at - https://github.com/curl/curl/issues/685 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -164,13 +169,13 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -- --Added in 7.48.0. -+# HISTORY - - This option supersedes CURLINFO_TLS_SESSION(3) which was added in 7.34.0. - This option is exactly the same as that option except in the case of OpenSSL. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md b/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md -index 022960590..f752a23de 100644 ---- a/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md -+++ b/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.4.1 - --- - - # NAME -@@ -35,6 +36,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.4.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md b/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md -index 0bff41bd4..0b0d16ab7 100644 ---- a/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md -+++ b/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - # NAME - -@@ -35,6 +36,8 @@ When a redirect is followed, the time from each request is added together. - - See also the TIMES overview in the curl_easy_getinfo(3) man page. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_USED_PROXY.md b/docs/libcurl/opts/CURLINFO_USED_PROXY.md -index 7b38ea027..aeabb97af 100644 ---- a/docs/libcurl/opts/CURLINFO_USED_PROXY.md -+++ b/docs/libcurl/opts/CURLINFO_USED_PROXY.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 8.7.0 - --- - - # NAME -@@ -31,6 +32,8 @@ CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_USED_PROXY, - Pass a pointer to a long. It gets set to zero set if no proxy was used in the - previous transfer or a non-zero value if a proxy was used. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(int argc, char *argv[]) - } - ~~~ - --# AVAILABILITY -- --Added in 8.7.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLINFO_XFER_ID.md b/docs/libcurl/opts/CURLINFO_XFER_ID.md -index 0855ac9a1..f87559321 100644 ---- a/docs/libcurl/opts/CURLINFO_XFER_ID.md -+++ b/docs/libcurl/opts/CURLINFO_XFER_ID.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_setopt (3) - Protocol: - - All -+Added-in: 8.2.0 - --- - - # NAME -@@ -35,6 +36,8 @@ The transfer id is unique among all transfers performed using the same - connection cache. This is implicitly the case for all transfers in the - same multi handle. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 8.2.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md b/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md -index e292792ee..ff232ed64 100644 ---- a/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md -+++ b/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md -@@ -10,6 +10,7 @@ See-also: - - CURLMOPT_PIPELINING (3) - Protocol: - - HTTP -+Added-in: 7.30.0 - --- - - # NAME -@@ -37,7 +38,9 @@ than CURLMOPT_MAX_PIPELINE_LENGTH(3). - - # DEFAULT - --The default value is 0, which means that the penalization is inactive. -+0, which means that penalization is inactive. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md b/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md -index 8f0783b60..bbd90553e 100644 ---- a/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md -+++ b/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_PIPELINING (3) - Protocol: - - HTTP -+Added-in: 7.30.0 - --- - - # NAME -@@ -36,7 +37,9 @@ CURLMOPT_MAX_PIPELINE_LENGTH(3). - - # DEFAULT - --The default value is 0, which means that the size penalization is inactive. -+0, which means that the size penalization is inactive. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -49,9 +52,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md b/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md -index 1e5a947ed..9e9a55ff0 100644 ---- a/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md -+++ b/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAXCONNECTS (3) - Protocol: - - All -+Added-in: 7.16.3 - --- - - # NAME -@@ -25,17 +26,16 @@ CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAXCONNECTS, long max); - - # DESCRIPTION - --Pass a long indicating the **max**. The set number is used as the maximum --amount of simultaneously open connections that libcurl may keep in its --connection cache after completed use. By default libcurl enlarges the size for --each added easy handle to make it fit 4 times the number of added easy --handles. -+Pass a long indicating the **max**, the maximum amount of connections that -+libcurl may keep alive in its connection cache after use. By default libcurl -+enlarges the size for each added easy handle to make it fit 4 times the number -+of added easy handles. - --By setting this option, you can prevent the cache size from growing beyond the -+By setting this option, you prevent the cache size from growing beyond the - limit set by you. - --When the cache is full, curl closes the oldest one in the cache to prevent the --number of open connections from increasing. -+When the cache is full, curl closes the oldest connection present in the cache -+to prevent the number of connections from increasing. - - This option is for the multi handle's use only, when using the easy interface - you should instead use the CURLOPT_MAXCONNECTS(3) option. -@@ -45,13 +45,15 @@ connections. - - Changing this value when there are transfers in progress is possible, and the - new value is then used the next time checks are performed. Lowering the value --does however not close down any active transfers, it simply does not allow new --ones to get made. -+does not close down any active transfers, it simply does not allow new ones to -+get made. - - # DEFAULT - - See DESCRIPTION - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -63,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md b/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md -index b8e7fefdb..c628ca2bc 100644 ---- a/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md -+++ b/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAXCONNECTS (3) - Protocol: - - HTTP -+Added-in: 7.67.0 - --- - - # NAME -@@ -37,6 +38,8 @@ value passed here would be honored based on other system resources properties. - - 100 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -48,9 +51,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.67.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md b/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md -index f798a4626..07fa6bf6d 100644 ---- a/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md -+++ b/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_MAX_TOTAL_CONNECTIONS (3) - Protocol: - - All -+Added-in: 7.30.0 - --- - - # NAME -@@ -26,35 +27,38 @@ CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_HOST_CONNECTIONS, - - # DESCRIPTION - --Pass a long to indicate **max**. The set number is used as the maximum amount --of simultaneously open connections to a single host (a host being the same as --a hostname + port number pair). For each new session to a host, libcurl might --open a new connection up to the limit set by CURLMOPT_MAX_HOST_CONNECTIONS(3). --When the limit is reached, new sessions are kept pending until a connection --becomes available. -+Pass a long to indicate **max**, the maximum amount of simultaneously open -+connections libcurl may hold a single host (a host being the same as a -+hostname + port number pair). For each new transfer to the same host, libcurl -+might open a new connection up to the limit set by -+CURLMOPT_MAX_HOST_CONNECTIONS(3). When the limit is reached, new sessions are -+kept pending until a connection becomes available. - - The default **max** value is 0, unlimited. This set limit is also used for - proxy connections, and then the proxy is considered to be the host for which - this limit counts. - - When more transfers are added to the multi handle than what can be performed --due to the set limit, they are queued up waiting for their chance. When that --happens, the CURLOPT_TIMEOUT_MS(3) timeout is inclusive of the waiting time, --meaning that if you set a too narrow timeout in such a case the transfer might --never even start before it times out. -+due to the set limit, they are queued up waiting for their chance. - --Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3) timeout is --however treated as a per-connect timeout. -+While a transfer is queued up internally waiting for a connection, the -+CURLOPT_TIMEOUT_MS(3) timeout is counted inclusive of the waiting time, -+meaning that if you set a too narrow timeout the transfer might never even -+start before it times out. The CURLOPT_CONNECTTIMEOUT_MS(3) time is also -+similarly still treated as a per-connect timeout and might expire even before -+making a new connection is permitted. - --Changing this value when there are transfers in progress is possible, and the --new value is then used the next time checks are performed. Lowering the value --does however not close down any active transfers, it simply does not allow new --ones to get made. -+Changing this value while there are transfers in progress is possible. The new -+value is then used the next time checks are performed. Lowering the value does -+not close down any active transfers, it simply does not allow new ones to get -+made. - - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md b/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md -index 84ab65e62..9da9994ab 100644 ---- a/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md -+++ b/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_PIPELINING (3) - Protocol: - - All -+Added-in: 7.30.0 - --- - - # NAME -@@ -42,6 +43,8 @@ CURLMOPT_MAX_PIPELINE_LENGTH(3). - - 5 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md b/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md -index a227a9cce..b014453a8 100644 ---- a/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md -+++ b/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_MAX_HOST_CONNECTIONS (3) - Protocol: - - All -+Added-in: 7.30.0 - --- - - # NAME -@@ -29,24 +30,31 @@ CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, - Pass a long for the **amount**. The set number is used as the maximum number - of simultaneously open connections in total using this multi handle. For each - new session, libcurl might open a new connection up to the limit set by --CURLMOPT_MAX_TOTAL_CONNECTIONS(3). When the limit is reached, new --sessions are held pending until there are available connections. If --CURLMOPT_PIPELINING(3) is enabled, libcurl can try multiplexing if the --host is capable of it. -+CURLMOPT_MAX_TOTAL_CONNECTIONS(3). If CURLMOPT_PIPELINING(3) is enabled, -+libcurl can try multiplexing if the host is capable of it. - - When more transfers are added to the multi handle than what can be performed --due to the set limit, they get queued up waiting for their chance. When that --happens, the CURLOPT_TIMEOUT_MS(3) timeout is counted inclusive of the --waiting time, meaning that if you set a too narrow timeout in such a case the --transfer might never even start before it times out. -+due to the set limit, they get queued up waiting for their chance. - --Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3) --timeout is however treated as a per-connect timeout. -+While a transfer is queued up internally waiting for a connection, the -+CURLOPT_TIMEOUT_MS(3) timeout is counted inclusive of the waiting time, -+meaning that if you set a too narrow timeout the transfer might never even -+start before it times out. The CURLOPT_CONNECTTIMEOUT_MS(3) time is also -+similarly still treated as a per-connect timeout and might expire even before -+making a new connection is permitted. -+ -+Changing this value while there are transfers in progress is possible. The new -+value is then used the next time checks are performed. Lowering the value does -+not close down any active transfers, it simply does not allow new ones to get -+made. - - # DEFAULT - --The default value is 0, which means that there is no limit. It is then simply --controlled by the number of easy handles added. -+0, which means that there is no limit. It is then simply controlled by the -+number of easy handles added concurrently and how much multiplexing is being -+done. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -59,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING.md b/docs/libcurl/opts/CURLMOPT_PIPELINING.md -index 66570a823..5fba662a1 100644 ---- a/docs/libcurl/opts/CURLMOPT_PIPELINING.md -+++ b/docs/libcurl/opts/CURLMOPT_PIPELINING.md -@@ -13,11 +13,12 @@ See-also: - - CURLMOPT_PIPELINING_SITE_BL (3) - Protocol: - - HTTP -+Added-in: 7.16.0 - --- - - # NAME - --CURLMOPT_PIPELINING - enable HTTP pipelining and multiplexing -+CURLMOPT_PIPELINING - enable HTTP multiplexing - - # SYNOPSIS - -@@ -29,15 +30,15 @@ CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_PIPELINING, long bitmask); - - # DESCRIPTION - --Pass in the correct value in the **bitmask** parameter to instruct libcurl --to enable multiplexing for this multi handle. -+Pass in the correct value in the **bitmask** parameter to instruct libcurl to -+enable multiplexing for this multi handle. - - With multiplexing enabled, libcurl attempts to do multiple transfers over the - same connection when doing parallel transfers to the same hosts. - - ## CURLPIPE_NOTHING (0) - --Default, which means doing no attempts at multiplexing. -+Make no attempts at multiplexing. - - ## CURLPIPE_HTTP1 (1) - -@@ -50,9 +51,9 @@ existing connection if possible. This requires HTTP/2 or HTTP/3. - - # DEFAULT - --Since 7.62.0, **CURLPIPE_MULTIPLEX** is enabled by default. -+**CURLPIPE_MULTIPLEX** - --Before that, default was **CURLPIPE_NOTHING**. -+# %PROTOCOLS% - - # EXAMPLE - -@@ -65,10 +66,16 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+The multiplex support bit was added in 7.43.0. HTTP/1 Pipelining support was -+disabled in 7.62.0. -+ -+Since 7.62.0, **CURLPIPE_MULTIPLEX** is enabled by default. -+ -+Before that, default was **CURLPIPE_NOTHING**. - --Added in 7.16.0. Multiplex support bit added in 7.43.0. HTTP/1 Pipelining --support was disabled in 7.62.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md b/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md -index 0fc11fdc3..b009de81c 100644 ---- a/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md -+++ b/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_PIPELINING_SITE_BL (3) - Protocol: - - HTTP -+Added-in: 7.30.0 - --- - - # NAME -@@ -41,7 +42,9 @@ Pass a NULL pointer to clear the block list. - - # DEFAULT - --The default value is NULL, which means that there is no block list. -+NULL, which means that there is no block list. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md b/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md -index dc009a27d..9e9e20ac1 100644 ---- a/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md -+++ b/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_PIPELINING_SERVER_BL (3) - Protocol: - - HTTP -+Added-in: 7.30.0 - --- - - # NAME -@@ -36,7 +37,9 @@ Pass a NULL pointer to clear the block list. - - # DEFAULT - --The default value is NULL, which means that there is no block list. -+NULL, which means that there is no block list. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.30.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_PUSHDATA.md b/docs/libcurl/opts/CURLMOPT_PUSHDATA.md -index 23399d17d..5499225da 100644 ---- a/docs/libcurl/opts/CURLMOPT_PUSHDATA.md -+++ b/docs/libcurl/opts/CURLMOPT_PUSHDATA.md -@@ -11,6 +11,7 @@ See-also: - - RFC 7540 - Protocol: - - HTTP -+Added-in: 7.44.0 - --- - - # NAME -@@ -35,6 +36,8 @@ libcurl itself, only passed on to the callback function. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,9 +79,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.44.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md -index c80112839..d8f800380 100644 ---- a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md -+++ b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md -@@ -11,6 +11,7 @@ See-also: - - RFC 7540 - Protocol: - - HTTP -+Added-in: 7.44.0 - --- - - # NAME -@@ -96,6 +97,8 @@ All other return codes are reserved for future use. - - NULL, no callback - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -137,9 +140,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.44.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md b/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md -index 7aea20c44..aade927a1 100644 ---- a/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md -+++ b/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md -@@ -10,6 +10,7 @@ See-also: - - curl_multi_socket_action (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -36,6 +37,8 @@ callback's **clientp** argument. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md b/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md -index a16747c04..60c1185ea 100644 ---- a/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md -+++ b/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - curl_multi_socket_action (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -49,6 +50,9 @@ libcurl by calling curl_multi_socket_action(3). - # CALLBACK ARGUMENTS - - *easy* identifies the specific transfer for which this update is related. -+Since this callback manages a whole multi handle, an application should not -+make assumptions about which particular handle that is passed here. It might -+even be an internal easy handle that the application did not add itself. - - *s* is the specific socket this function invocation concerns. If the - **what** argument is not CURL_POLL_REMOVE then it holds information about -@@ -89,6 +93,8 @@ active transfer. It might soon be added again. - - NULL (no callback) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -124,9 +130,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_TIMERDATA.md b/docs/libcurl/opts/CURLMOPT_TIMERDATA.md -index fb830b1fb..4f0ce4e73 100644 ---- a/docs/libcurl/opts/CURLMOPT_TIMERDATA.md -+++ b/docs/libcurl/opts/CURLMOPT_TIMERDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_TIMERFUNCTION (3) - Protocol: - - All -+Added-in: 7.16.0 - --- - - # NAME -@@ -35,6 +36,8 @@ callback's **clientp** argument. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md b/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md -index 85f9957a7..35fabdc7b 100644 ---- a/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md -+++ b/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLMOPT_TIMERDATA (3) - Protocol: - - All -+Added-in: 7.16.0 - --- - - # NAME -@@ -22,7 +23,7 @@ CURLMOPT_TIMERFUNCTION - callback to receive timeout values - - int timer_callback(CURLM *multi, /* multi handle */ - long timeout_ms, /* timeout in number of ms */ -- void *clientp); /* private callback pointer */ -+ void *clientp); /* private callback pointer */ - - CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERFUNCTION, timer_callback); - ~~~ -@@ -35,11 +36,15 @@ shown above. - Certain features, such as timeouts and retries, require you to call libcurl - even when there is no activity on the file descriptors. - --Your callback function **timer_callback** should install a non-repeating --timer with an expire time of **timeout_ms** milliseconds. When that timer --fires, call either curl_multi_socket_action(3) or -+Your callback function **timer_callback** should install a single -+non-repeating timer with an expire time of **timeout_ms** milliseconds. When -+that timer fires, call either curl_multi_socket_action(3) or - curl_multi_perform(3), depending on which interface you use. - -+If this callback is called when a timer is already running, this new expire -+time *replaces* the former timeout. The application should then effectively -+cancel the old timeout and set a new timeout using this new expire time. -+ - A **timeout_ms** value of -1 passed to this callback means you should delete - the timer. All other values are valid expire times in number of milliseconds. - -@@ -48,21 +53,23 @@ The **timer_callback** is called when the timeout expire time is changed. - The **clientp** pointer is set with CURLMOPT_TIMERDATA(3). - - The timer callback should return 0 on success, and -1 on error. If this --callback returns error, **all** transfers currently in progress in this --multi handle are aborted and made to fail. -+callback returns error, **all** transfers currently in progress in this multi -+handle are aborted and made to fail. - - This callback can be used instead of, or in addition to, - curl_multi_timeout(3). - --**WARNING:** do not call libcurl directly from within the callback itself --when the **timeout_ms** value is zero, since it risks triggering an --unpleasant recursive behavior that immediately calls another call to the --callback with a zero timeout... -+**WARNING:** do not call libcurl directly from within the callback itself when -+the **timeout_ms** value is zero, since it risks triggering an unpleasant -+recursive behavior that immediately calls another call to the callback with a -+zero timeout... - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -72,15 +79,15 @@ struct priv { - - static int timerfunc(CURLM *multi, long timeout_ms, void *clientp) - { -- struct priv *mydata = clientp; -- printf("our ptr: %p\n", mydata->custom); -- -- if(timeout_ms) { -- /* this is the new single timeout to wait for */ -- } -- else { -- /* delete the timeout, nothing to wait for now */ -- } -+ struct priv *mydata = clientp; -+ printf("our ptr: %p\n", mydata->custom); -+ -+ if(timeout_ms) { -+ /* this is the new single timeout to wait for */ -+ } -+ else { -+ /* delete the timeout, nothing to wait for now */ -+ } - } - - int main(void) -@@ -92,9 +99,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md -index c34acbd63..c2b3a3ca1 100644 ---- a/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md -+++ b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md -@@ -9,6 +9,7 @@ See-also: - - unix (7) - Protocol: - - All -+Added-in: 7.53.0 - --- - - # NAME -@@ -42,7 +43,9 @@ share the same storage and therefore only one of them can be set per handle. - - # DEFAULT - --Default is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.53.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md -index f1db8fa69..90c1060e6 100644 ---- a/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_STDERR (3) - Protocol: - - FTP -+Added-in: 7.24.0 - --- - - # NAME -@@ -33,6 +34,8 @@ server to connect back to libcurl when an active FTP connection is used. - - 60000 milliseconds - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.24.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md b/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md -index c090ef318..d0ef75f79 100644 ---- a/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md -+++ b/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_TRANSFER_ENCODING (3) - Protocol: - - HTTP -+Added-in: 7.21.6 - --- - - # NAME -@@ -41,19 +42,19 @@ built-in supported encodings. - - Alternatively, you can specify exactly the encoding or list of encodings you - want in the response. The following encodings are supported: *identity*, --meaning non-compressed, *deflate* which requests the server to compress --its response using the zlib algorithm, *gzip* which requests the gzip --algorithm, (since curl 7.57.0) *br* which is brotli and (since curl --7.72.0) *zstd* which is zstd. Provide them in the string as a --comma-separated list of accepted encodings, like: **"br, gzip, deflate"**. -- --Set CURLOPT_ACCEPT_ENCODING(3) to NULL to explicitly disable it, which --makes libcurl not send an Accept-Encoding: header and not decompress received -+meaning non-compressed, *deflate* which requests the server to compress its -+response using the zlib algorithm, *gzip* which requests the gzip algorithm, -+(since curl 7.57.0) *br* which is brotli and (since curl 7.72.0) *zstd* which -+is zstd. Provide them in the string as a comma-separated list of accepted -+encodings, like: **"br, gzip, deflate"**. -+ -+Set CURLOPT_ACCEPT_ENCODING(3) to NULL to explicitly disable it, which makes -+libcurl not send an Accept-Encoding: header and not decompress received - contents automatically. - - You can also opt to just include the Accept-Encoding: header in your request --with CURLOPT_HTTPHEADER(3) but then there is no automatic decompressing --when receiving data. -+with CURLOPT_HTTPHEADER(3) but then there is no automatic decompressing when -+receiving data. - - This is a request, not an order; the server may or may not do it. This option - must be set (to any non-NULL value) or else any unsolicited encoding done by -@@ -71,10 +72,26 @@ sending the length of the non-compressed content is a common server mistake). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. -+ -+# HISTORY -+ -+This option was called CURLOPT_ENCODING before 7.21.6 -+ -+# NOTES -+ -+The specific libcurl you are using must have been built with zlib to be able to -+decompress gzip and deflate responses, with the brotli library to -+decompress brotli responses and with the zstd library to decompress zstd -+responses. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -93,14 +110,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This option was called CURLOPT_ENCODING before 7.21.6 -- --The specific libcurl you are using must have been built with zlib to be able to --decompress gzip and deflate responses, with the brotli library to --decompress brotli responses and with the zstd library to decompress zstd --responses. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md b/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md -index 24ea2e581..e8ac90c0e 100644 ---- a/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md -+++ b/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_STDERR (3) - Protocol: - - All -+Added-in: 7.19.0 - --- - - # NAME -@@ -31,6 +32,8 @@ Pass a long specifying the scope id value to use when connecting to IPv6 address - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ALTSVC.md b/docs/libcurl/opts/CURLOPT_ALTSVC.md -index 8ca2de4be..ef5e83450 100644 ---- a/docs/libcurl/opts/CURLOPT_ALTSVC.md -+++ b/docs/libcurl/opts/CURLOPT_ALTSVC.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_RESOLVE (3) - Protocol: - - HTTP -+Added-in: 7.64.1 - --- - - # NAME -@@ -34,10 +35,18 @@ CURLOPT_ALTSVC_CTRL(3). - - Specify a blank filename ("") to make libcurl not load from a file at all. - -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL. The alt-svc cache is not read nor written to file. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -100,9 +109,7 @@ Boolean (1 or 0) if "persist" was set for this entry - - Integer priority value (not currently used) - --# AVAILABILITY -- --Added in 7.64.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md b/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md -index 971f33fcb..190d28f97 100644 ---- a/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md -+++ b/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_RESOLVE (3) - Protocol: - - HTTP -+Added-in: 7.64.1 - --- - - # NAME -@@ -34,7 +35,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ALTSVC_CTRL, long bitmask); - Populate the long *bitmask* with the correct set of features to instruct - libcurl how to handle Alt-Svc for the transfers using this handle. - --libcurl only accepts Alt-Svc headers over a secure transport, meaning -+libcurl only accepts Alt-Svc headers over a Secure Transport, meaning - HTTPS. It also only completes a request to an alternative origin if that - origin is properly hosted over HTTPS. These requirements are there to make - sure both the source and the destination are legitimate. -@@ -43,6 +44,11 @@ Alternative services are only used when setting up new connections. If there - exists an existing connection to the host in the connection pool, then that is - preferred. - -+If CURLOPT_ALTSVC(3) is set, CURLOPT_ALTSVC_CTRL(3) gets a default value -+corresponding to CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2 -+and HTTP/3 bits are only set if libcurl was built with support for those -+versions. -+ - Setting any bit enables the alt-svc engine. - - ## CURLALTSVC_READONLYFILE -@@ -67,10 +73,9 @@ was also built to actually support HTTP/3, otherwise this bit is ignored. - - # DEFAULT - --Alt-Svc handling is disabled by default. If CURLOPT_ALTSVC(3) is set, --CURLOPT_ALTSVC_CTRL(3) has a default value corresponding to --CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2 and HTTP/3 bits are --only set if libcurl was built with support for those versions. -+0 - Alt-Svc handling is disabled -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -86,9 +91,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.64.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_APPEND.md b/docs/libcurl/opts/CURLOPT_APPEND.md -index 6c5142b49..867cace74 100644 ---- a/docs/libcurl/opts/CURLOPT_APPEND.md -+++ b/docs/libcurl/opts/CURLOPT_APPEND.md -@@ -10,6 +10,8 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - FTP -+ - SFTP -+Added-in: 7.17.0 - --- - - # NAME -@@ -33,6 +35,8 @@ instead of overwrite it. This is only useful when uploading to an FTP site. - - 0 (disabled) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,10 +54,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - This option was known as CURLOPT_FTPAPPEND up to 7.16.4 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_AUTOREFERER.md b/docs/libcurl/opts/CURLOPT_AUTOREFERER.md -index 754dee3ba..5106d84c8 100644 ---- a/docs/libcurl/opts/CURLOPT_AUTOREFERER.md -+++ b/docs/libcurl/opts/CURLOPT_AUTOREFERER.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_REFERER (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -43,6 +44,8 @@ referer header after the transfer. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md b/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md -index adb6d6afd..0b17b1ed7 100644 ---- a/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md -+++ b/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_PROXYAUTH (3) - Protocol: - - HTTP -+Added-in: 7.75.0 - --- - - # NAME -@@ -50,23 +51,34 @@ It is extracted from the hostname specified in the URL if omitted. - The argument is a function provided by a cloud. It is extracted from the - hostname specified in the URL if omitted. - --NOTE: This call set CURLOPT_HTTPAUTH(3) to CURLAUTH_AWS_SIGV4. --Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same --as calling this with **"aws:amz"** in parameter. -+## -+ -+NOTE: This call set CURLOPT_HTTPAUTH(3) to CURLAUTH_AWS_SIGV4. Calling -+CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same as calling this with -+**"aws:amz"** in parameter. - - Example with "Test:Try", when curl uses the algorithm, it generates --**"TEST-HMAC-SHA256"** for "Algorithm", **"x-try-date"** and --**"X-Try-Date"** for "date", **"test4_request"** for "request type", -+**"TEST-HMAC-SHA256"** for "Algorithm", **"x-try-date"** and **"X-Try-Date"** -+for "date", **"test4_request"** for "request type", - **"SignedHeaders=content-type;host;x-try-date"** for "signed headers" - - If you use just "test", instead of "test:try", test is used for every - generated string. - -+Setting CURLOPT_HTTPAUTH(3) with the CURLAUTH_AWS_SIGV4 bit set is the same as -+setting this option with a **"aws:amz"** parameter. -+ -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --By default, the value of this parameter is NULL. --Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same --as calling this with **"aws:amz"** in parameter. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -91,19 +103,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.75.0 -- --# RETURN VALUE -- --Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -- - # NOTES - - This option overrides the other auth types you might have set in --CURLOPT_HTTPAUTH(3) which should be highlighted as this makes this auth --method special. This method cannot be combined with other auth types. -+CURLOPT_HTTPAUTH(3) which should be highlighted as this makes this auth method -+special. This method cannot be combined with other auth types. - - A sha256 checksum of the request payload is used as input to the signature - calculation. For POST requests, this is a checksum of the provided -@@ -111,6 +115,12 @@ CURLOPT_POSTFIELDS(3). Otherwise, it is the checksum of an empty buffer. For - requests like PUT, you can provide your own checksum in an HTTP header named - **x-provider2-content-sha256**. - --For **aws:s3**, a **x-amz-content-sha256** header is added to every request --if not already present. For s3 requests with unknown payload, this header takes -+For **aws:s3**, a **x-amz-content-sha256** header is added to every request if -+not already present. For s3 requests with unknown payload, this header takes - the special value "UNSIGNED-PAYLOAD". -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md b/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md -index d2c13b6b3..5225dedf3 100644 ---- a/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md -+++ b/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME -@@ -53,6 +54,8 @@ allocated as long as there are active transfers. - - CURL_MAX_WRITE_SIZE (16kB) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -73,9 +76,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10. Growing the buffer was added in 7.53.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CAINFO.md b/docs/libcurl/opts/CURLOPT_CAINFO.md -index 87d1a8809..686d17e05 100644 ---- a/docs/libcurl/opts/CURLOPT_CAINFO.md -+++ b/docs/libcurl/opts/CURLOPT_CAINFO.md -@@ -15,6 +15,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.4.2 - --- - - # NAME -@@ -53,6 +54,9 @@ store of root certificates (the default for Schannel). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - The default value for this can be figured out with CURLINFO_CAINFO(3). - - # DEFAULT -@@ -60,6 +64,8 @@ The default value for this can be figured out with CURLINFO_CAINFO(3). - Built-in system specific. When curl is built with Secure Transport or - Schannel, this option is not set by default. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,10 +81,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Schannel support added in libcurl 7.60. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md -index d65024325..39b1f9873 100644 ---- a/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md -@@ -19,6 +19,7 @@ TLS-backend: - - wolfSSL - - Secure Transport - - Schannel -+Added-in: 7.77.0 - --- - - # NAME -@@ -53,6 +54,8 @@ This option overrides CURLOPT_CAINFO(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,14 +79,14 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.77.0. -+# HISTORY - - This option is supported by the BearSSL (since 7.79.0), mbedTLS (since --7.81.0), rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure -+7.81.0), Rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure - Transport and Schannel backends. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_CAPATH.md b/docs/libcurl/opts/CURLOPT_CAPATH.md -index 08caf762a..3dcba2d0a 100644 ---- a/docs/libcurl/opts/CURLOPT_CAPATH.md -+++ b/docs/libcurl/opts/CURLOPT_CAPATH.md -@@ -16,6 +16,7 @@ TLS-backend: - - GnuTLS - - mbedTLS - - wolfSSL -+Added-in: 7.9.8 - --- - - # NAME -@@ -44,11 +45,16 @@ to some limitation in OpenSSL. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - The default value for this can be figured out with CURLINFO_CAPATH(3). - - # DEFAULT - --A default path detected at build time. -+A path detected at build time. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -66,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This option is supported by the OpenSSL, GnuTLS, mbedTLS and wolfSSL backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md -index aa479b6be..725efc365 100644 ---- a/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md -+++ b/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md -@@ -13,7 +13,11 @@ See-also: - Protocol: - - TLS - TLS-backend: -+ - GnuTLS - - OpenSSL -+ - Schannel -+ - wolfSSL -+Added-in: 7.87.0 - --- - - # NAME -@@ -31,21 +35,24 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CA_CACHE_TIMEOUT, long age); - # DESCRIPTION - - Pass a long, this sets the timeout in seconds. This tells libcurl the maximum --time any cached certificate store it has in memory may be kept and reused for --new connections. Once the timeout has expired, a subsequent fetch requiring a --certificate has to reload it. -+time any cached CA certificate store it has in memory may be kept and reused -+for new connections. Once the timeout has expired, a subsequent fetch -+requiring a CA certificate has to reload it. - --Building a certificate store from a CURLOPT_CAINFO(3) file is a slow --operation so curl may cache the generated certificate store internally to speed --up future connections. -+Building a CA certificate store from a CURLOPT_CAINFO(3) file is a slow -+operation so curl may cache the generated certificate store internally to -+speed up future connections. - --Set to zero to completely disable caching, or set to -1 to retain the cached --store remain forever. By default, libcurl caches this info for 24 hours. -+Set the timeout to zero to completely disable caching, or set to -1 to retain -+the cached store remain forever. By default, libcurl caches this info for 24 -+hours. - - # DEFAULT - - 86400 (24 hours) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -70,12 +77,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - --This option was added in curl 7.87.0. -+This option is supported by OpenSSL and its forks (since 7.87.0), Schannel -+(since 8.5.0), wolfSSL (since 8.9.0) and GnuTLS (since 8.9.0). - --This option is supported by OpenSSL and its forks (since 7.87.0) and Schannel --(since 8.5.0). -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CERTINFO.md b/docs/libcurl/opts/CURLOPT_CERTINFO.md -index 71339cd03..abceeb46d 100644 ---- a/docs/libcurl/opts/CURLOPT_CERTINFO.md -+++ b/docs/libcurl/opts/CURLOPT_CERTINFO.md -@@ -17,6 +17,7 @@ TLS-backend: - - GnuTLS - - Schannel - - Secure Transport -+Added-in: 7.19.1 - --- - - # NAME -@@ -43,6 +44,8 @@ its option CURLINFO_CERTINFO(3). - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -82,9 +85,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Schannel support added in 7.50.0. Secure Transport support added in 7.79.0. -+mbedTLS support added in 8.9.0. -+ -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md -index 01b6f78dc..7d9af2ea3 100644 ---- a/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WILDCARDMATCH (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -23,7 +24,7 @@ CURLOPT_CHUNK_BGN_FUNCTION - callback before a transfer with FTP wildcard match - struct curl_fileinfo { - char *filename; - curlfiletype filetype; -- time_t time; /* always zero! */ -+ time_t time; /* always zero */ - unsigned int perm; - int uid; - int gid; -@@ -83,6 +84,8 @@ Return *CURL_CHUNK_BGN_FUNC_OK* if everything is fine, - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -141,9 +144,7 @@ int main() - } - ~~~ - --# AVAILABILITY -- --This was added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md b/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md -index b501138e9..5a7ebd6a3 100644 ---- a/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md -+++ b/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WILDCARDMATCH (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -33,6 +34,8 @@ CURLOPT_CHUNK_END_FUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -91,9 +94,7 @@ int main() - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md -index 295e29ea9..30a2efb12 100644 ---- a/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WILDCARDMATCH (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -41,6 +42,8 @@ Return *CURL_CHUNK_END_FUNC_OK* if everything is fine or - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main() - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md b/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md -index 7353af9ae..deea601cf 100644 ---- a/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md -+++ b/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_OPENSOCKETFUNCTION (3) - Protocol: - - All -+Added-in: 7.21.7 - --- - - # NAME -@@ -32,7 +33,9 @@ CURLOPT_CLOSESOCKETFUNCTION(3). - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md -index 18e3bfe71..060df3a05 100644 ---- a/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_OPENSOCKETFUNCTION (3) - Protocol: - - All -+Added-in: 7.21.7 - --- - - # NAME -@@ -43,7 +44,9 @@ closed. - - # DEFAULT - --By default libcurl uses the standard socket close function. -+Use the standard socket close function. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -75,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md -index f8e51d88e..83ccfcd27 100644 ---- a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md -+++ b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md -@@ -5,12 +5,12 @@ Title: CURLOPT_CONNECTTIMEOUT - Section: 3 - Source: libcurl - See-also: -- - CURLOPT_CONNECTTIMEOUT_MS (3) - - CURLOPT_LOW_SPEED_LIMIT (3) - - CURLOPT_MAX_RECV_SPEED_LARGE (3) - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.7 - --- - - # NAME -@@ -27,22 +27,22 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT, long timeout); - - # DESCRIPTION - --Pass a long. It should contain the maximum time in seconds that you allow the --connection phase to the server to take. This timeout only limits the --connection phase, it has no impact once it has connected. Set to zero to --switch to the default built-in connection timeout - 300 seconds. See also the --CURLOPT_TIMEOUT(3) option. -+Pass a long. It sets the maximum time in seconds that you allow the connection -+phase to take. This timeout only limits the connection phase, it has no impact -+once libcurl has connected. The connection phase includes the name resolve -+(DNS) and all protocol handshakes and negotiations until there is an -+established connection with the remote side. -+ -+Set this option to zero to switch to the default built-in connection timeout - -+300 seconds. See also the CURLOPT_TIMEOUT(3) option. - - CURLOPT_CONNECTTIMEOUT_MS(3) is the same function but set in milliseconds. - - If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3) - are set, the value set last is used. - --The "connection phase" is considered complete when the requested TCP, TLS or --QUIC handshakes are done. -- --The connection timeout set with CURLOPT_CONNECTTIMEOUT(3) is included in --the general all-covering CURLOPT_TIMEOUT(3). -+The connection timeout is included in the general all-covering -+CURLOPT_TIMEOUT(3): - - With CURLOPT_CONNECTTIMEOUT(3) set to 3 and CURLOPT_TIMEOUT(3) set - to 5, the operation can never last longer than 5 seconds, and the connection -@@ -53,13 +53,15 @@ to 2, the operation can never last longer than 2 seconds. Including the - connection phase. - - This option may cause libcurl to use the SIGALRM signal to timeout system --calls on builds not using asynch DNS. In unix-like systems, this might cause -+calls on builds not using asynch DNS. In Unix-like systems, this might cause - signals to be used unless CURLOPT_NOSIGNAL(3) is set. - - # DEFAULT - - 300 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -77,9 +79,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md -index 1c22fd872..cbfc6d3ad 100644 ---- a/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md -@@ -5,11 +5,12 @@ Title: CURLOPT_CONNECTTIMEOUT_MS - Section: 3 - Source: libcurl - See-also: -- - CURLOPT_CONNECTTIMEOUT (3) - - CURLOPT_LOW_SPEED_LIMIT (3) -- - CURLOPT_TIMEOUT (3) -+ - CURLOPT_MAX_RECV_SPEED_LARGE (3) -+ - CURLOPT_TIMEOUT_MS (3) - Protocol: - - All -+Added-in: 7.16.2 - --- - - # NAME -@@ -27,15 +28,41 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT_MS, - - # DESCRIPTION - --Pass a long. It should contain the maximum time in milliseconds that you allow --the connection phase to the server to take. -+Pass a long. It sets the maximum time in milliseconds that you allow the -+connection phase to take. This timeout only limits the connection phase, it -+has no impact once libcurl has connected. The connection phase includes the -+name resolve (DNS) and all protocol handshakes and negotiations until there is -+an established connection with the remote side. - --See CURLOPT_CONNECTTIMEOUT(3) for details. -+Set this option to zero to switch to the default built-in connection timeout - -+300 seconds. See also the CURLOPT_TIMEOUT_MS(3) option. -+ -+CURLOPT_CONNECTTIMEOUT(3) is the same function but set in seconds. -+ -+If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3) are set, -+the value set last is used. -+ -+The connection timeout is included in the general all-covering -+CURLOPT_TIMEOUT_MS(3): -+ -+With CURLOPT_CONNECTTIMEOUT_MS(3) set to 3000 and CURLOPT_TIMEOUT_MS(3) set to -+5000, the operation can never last longer than 5000 milliseconds, and the -+connection phase cannot last longer than 3000 milliseconds. -+ -+With CURLOPT_CONNECTTIMEOUT_MS(3) set to 4000 and CURLOPT_TIMEOUT_MS(3) set to -+2000, the operation can never last longer than 2000 milliseconds. Including -+the connection phase. -+ -+This option may cause libcurl to use the SIGALRM signal to timeout system -+calls on builds not using asynch DNS. In Unix-like systems, this might cause -+signals to be used unless CURLOPT_NOSIGNAL(3) is set. - - # DEFAULT - - 300000 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md b/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md -index 8fcb5a3b7..7b2e713af 100644 ---- a/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md -+++ b/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md -@@ -11,6 +11,7 @@ See-also: - - curl_easy_send (3) - Protocol: - - All -+Added-in: 7.15.2 - --- - - # NAME -@@ -54,6 +55,8 @@ curl_easy_recv(3) do not function. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,15 +69,17 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L); - ret = curl_easy_perform(curl); - if(ret == CURLE_OK) { -- /* only connected! */ -+ /* only connected */ - } - } - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+WS and WSS support added in 7.86.0. - --Added in 7.15.2. WS and WSS support added in 7.86.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CONNECT_TO.md b/docs/libcurl/opts/CURLOPT_CONNECT_TO.md -index 4714cb2bd..b4cc638ae 100644 ---- a/docs/libcurl/opts/CURLOPT_CONNECT_TO.md -+++ b/docs/libcurl/opts/CURLOPT_CONNECT_TO.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - All -+Added-in: 7.49.0 - --- - - # NAME -@@ -75,10 +76,15 @@ When this option is passed to curl_easy_setopt(3), libcurl does not copy the - list so you **must** keep it around until you no longer use this *handle* for - a transfer before you call curl_slist_free_all(3) on the list. - -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -103,9 +109,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.49.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md -index 6cde80b1f..6d233ef3a 100644 ---- a/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -72,6 +73,8 @@ You need to override these definitions if they are different on your system. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -100,13 +103,15 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Not available and deprecated since 7.82.0. - - Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was - built. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md -index 60cdcd0ed..9ea257f2b 100644 ---- a/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3) - - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) -+Added-in: 7.15.4 - --- - - # NAME -@@ -69,6 +70,8 @@ You need to override these definitions if they are different on your system. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -93,13 +96,15 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Not available and deprecated since 7.82.0. - - Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was - built. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md b/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md -index a8d22ed54..8644885ce 100644 ---- a/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_CONV_FROM_UTF8_FUNCTION (3) - Protocol: - - All -+Added-in: 7.15.4 - --- - - # NAME -@@ -71,6 +72,8 @@ You need to override these definitions if they are different on your system. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -96,13 +99,15 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Not available and deprecated since 7.82.0. - - Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was - built. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_COOKIE.md b/docs/libcurl/opts/CURLOPT_COOKIE.md -index 7c6ae67c7..c16a59376 100644 ---- a/docs/libcurl/opts/CURLOPT_COOKIE.md -+++ b/docs/libcurl/opts/CURLOPT_COOKIE.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_HTTPHEADER (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -34,7 +35,8 @@ NAME=CONTENTS, where NAME is the cookie name and CONTENTS is what the cookie - should contain. - - To set multiple cookies, set them all using a single option concatenated like --this: "name1=content1; name2=content2;" etc. -+this: "name1=content1; name2=content2;" etc. libcurl does not syntax check the -+data but assumes the application gives it what it needs to send. - - This option sets the cookie header explicitly in the outgoing request(s). If - multiple requests are done due to authentication, followed redirections or -@@ -42,33 +44,31 @@ similar, they all get this cookie passed on. - - The cookies set by this option are separate from the internal cookie storage - held by the cookie engine and they are not be modified by it. If you enable --the cookie engine and either you have imported a cookie of the same name --(e.g. 'foo') or the server has set one, it has no effect on the cookies you --set here. A request to the server sends both the 'foo' held by the cookie --engine and the 'foo' held by this option. To set a cookie that is instead held --by the cookie engine and can be modified by the server use --CURLOPT_COOKIELIST(3). -+the cookie engine and either you have imported a cookie of the same name (e.g. -+'foo') or the server has set one, it has no effect on the cookies you set -+here. A request to the server sends both the 'foo' held by the cookie engine -+and the 'foo' held by this option. To set a cookie that is instead held by the -+cookie engine and can be modified by the server use CURLOPT_COOKIELIST(3). - --Using this option multiple times makes the last set string override the --previous ones. -- --This option does not enable the cookie engine. Use CURLOPT_COOKIEFILE(3) --or CURLOPT_COOKIEJAR(3) to enable parsing and sending cookies --automatically. -+Since this custom cookie is appended to the Cookie: header in addition to any -+cookies set by the cookie engine, there is a risk that the header ends up too -+long and thereby getting the entire request rejected by the server. - - The application does not have to keep the string around after setting this - option. - --If libcurl is built with PSL (*Public Suffix List*) support, it detects and --discards cookies that are specified for such suffix domains that should not be --allowed to have cookies. If libcurl is *not* built with PSL support, it has no --ability to stop super cookies. PSL support is identified by the --**CURL_VERSION_PSL** feature bit returned by curl_version_info(3). -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+This option does not enable the cookie engine. Use CURLOPT_COOKIEFILE(3) or -+CURLOPT_COOKIEJAR(3) to enable parsing and sending cookies automatically. - - # DEFAULT - - NULL, no cookies - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -85,9 +85,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If HTTP is enabled -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_COOKIEFILE.md b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md -index 89ec0a43e..7f607c735 100644 ---- a/docs/libcurl/opts/CURLOPT_COOKIEFILE.md -+++ b/docs/libcurl/opts/CURLOPT_COOKIEFILE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_COOKIESESSION (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -47,14 +48,12 @@ domain cannot match the target URL's. To address this, set a domain in - Set-Cookie line (doing that includes subdomains) or preferably: use the - Netscape format. - --If you use this option multiple times, you add more files to read cookies --from. -- - The application does not have to keep the string around after setting this - option. - --Setting this option to NULL (since 7.77.0) explicitly disables the cookie --engine and clears the list of files to read cookies from. -+If you use this option multiple times, you add more files to read cookies -+from. Setting this option to NULL disables the cookie engine and clears the -+list of files to read cookies from. - - # SECURITY - -@@ -67,6 +66,8 @@ run. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -92,9 +93,7 @@ int main(void) - The cookie file format and general cookie concepts in curl are described - online here: https://curl.se/docs/http-cookies.html - --# AVAILABILITY -- --As long as HTTP is supported -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_COOKIEJAR.md b/docs/libcurl/opts/CURLOPT_COOKIEJAR.md -index f08e8078f..f9c17e853 100644 ---- a/docs/libcurl/opts/CURLOPT_COOKIEJAR.md -+++ b/docs/libcurl/opts/CURLOPT_COOKIEJAR.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_COOKIELIST (3) - Protocol: - - HTTP -+Added-in: 7.9 - --- - - # NAME -@@ -26,22 +27,21 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_COOKIEJAR, char *filename); - - # DESCRIPTION - --Pass a *filename* as a char *, null-terminated. This makes libcurl write --all internally known cookies to the specified file when --curl_easy_cleanup(3) is called. If no cookies are kept in memory at that --time, no file is created. Specify "-" as filename to instead have the cookies --written to stdout. Using this option also enables cookies for this session, so --if you for example follow a redirect it makes matching cookies get sent --accordingly. -+Pass a *filename* as a char *, null-terminated. This makes libcurl write all -+internally known cookies to the specified file when curl_easy_cleanup(3) is -+called. If no cookies are kept in memory at that time, no file is created. -+Specify "-" as filename to instead have the cookies written to stdout. Using -+this option also enables cookies for this session, so if you for example -+follow a redirect it makes matching cookies get sent accordingly. - - Note that libcurl does not read any cookies from the cookie jar specified with - this option. To read cookies from a file, use CURLOPT_COOKIEFILE(3). - - If the cookie jar file cannot be created or written to (when the --curl_easy_cleanup(3) is called), libcurl does not and cannot report an --error for this. Using CURLOPT_VERBOSE(3) or --CURLOPT_DEBUGFUNCTION(3) displays a warning, but that is the only --visible feedback you get about this possibly lethal situation. -+curl_easy_cleanup(3) is called), libcurl does not and cannot report an error -+for this. Using CURLOPT_VERBOSE(3) or CURLOPT_DEBUGFUNCTION(3) displays a -+warning, but that is the only visible feedback you get about this possibly -+lethal situation. - - Cookies are imported in the Set-Cookie format without a domain name are not - exported by this option. -@@ -49,10 +49,15 @@ exported by this option. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,15 +73,13 @@ int main(void) - - res = curl_easy_perform(curl); - -- /* close the handle, write the cookies! */ -+ /* close the handle, write the cookies */ - curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_COOKIELIST.md b/docs/libcurl/opts/CURLOPT_COOKIELIST.md -index 7be0c1deb..d7a6c0b12 100644 ---- a/docs/libcurl/opts/CURLOPT_COOKIELIST.md -+++ b/docs/libcurl/opts/CURLOPT_COOKIELIST.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_COOKIEJAR (3) - Protocol: - - HTTP -+Added-in: 7.14.1 - --- - - # NAME -@@ -69,6 +70,8 @@ loads all cookies from the files specified by CURLOPT_COOKIEFILE(3) - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -118,7 +121,7 @@ int main(void) - The cookie file format and general cookie concepts in curl are described - online here: https://curl.se/docs/http-cookies.html - --# AVAILABILITY -+# HISTORY - - **ALL** was added in 7.14.1 - -@@ -128,6 +131,8 @@ online here: https://curl.se/docs/http-cookies.html - - **RELOAD** was added in 7.39.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_COOKIESESSION.md b/docs/libcurl/opts/CURLOPT_COOKIESESSION.md -index 705b1b7d8..19b9a301d 100644 ---- a/docs/libcurl/opts/CURLOPT_COOKIESESSION.md -+++ b/docs/libcurl/opts/CURLOPT_COOKIESESSION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_COOKIEJAR (3) - Protocol: - - HTTP -+Added-in: 7.9.7 - --- - - # NAME -@@ -41,6 +42,8 @@ the same session. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md b/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md -index a48374014..a014458c9 100644 ---- a/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md -+++ b/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - HTTP -+Added-in: 7.17.1 - --- - - # NAME -@@ -32,19 +33,26 @@ HTTP POST operation. It behaves as the CURLOPT_POSTFIELDS(3) option, but the - original data is instead copied by the library, allowing the application to - overwrite the original data after setting this option. - --Because data are copied, care must be taken when using this option in --conjunction with CURLOPT_POSTFIELDSIZE(3) or --CURLOPT_POSTFIELDSIZE_LARGE(3): If the size has not been set prior to --CURLOPT_COPYPOSTFIELDS(3), the data is assumed to be a null-terminated --string; else the stored size informs the library about the byte count to --copy. In any case, the size must not be changed after --CURLOPT_COPYPOSTFIELDS(3), unless another CURLOPT_POSTFIELDS(3) or --CURLOPT_COPYPOSTFIELDS(3) option is issued. -+Because data is copied, care must be taken when using this option in -+conjunction with CURLOPT_POSTFIELDSIZE(3) or CURLOPT_POSTFIELDSIZE_LARGE(3). -+If the size has not been set prior to CURLOPT_COPYPOSTFIELDS(3), the data is -+assumed to be a null-terminated string; else the stored size informs the -+library about the byte count to copy. In any case, the size must not be -+changed after CURLOPT_COPYPOSTFIELDS(3), unless another CURLOPT_POSTFIELDS(3) -+or CURLOPT_COPYPOSTFIELDS(3) option is set. -+ -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.17.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CRLF.md b/docs/libcurl/opts/CURLOPT_CRLF.md -index e49be9893..8c0c9a592 100644 ---- a/docs/libcurl/opts/CURLOPT_CRLF.md -+++ b/docs/libcurl/opts/CURLOPT_CRLF.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_CONV_TO_NETWORK_FUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -35,6 +36,8 @@ This is a legacy option of questionable use. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --SMTP since 7.40.0, other protocols since they were introduced -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CRLFILE.md b/docs/libcurl/opts/CURLOPT_CRLFILE.md -index b544f3777..f0bea2821 100644 ---- a/docs/libcurl/opts/CURLOPT_CRLFILE.md -+++ b/docs/libcurl/opts/CURLOPT_CRLFILE.md -@@ -14,6 +14,8 @@ TLS-backend: - - GnuTLS - - mbedTLS - - OpenSSL -+ - rustls -+Added-in: 7.19.0 - --- - - # NAME -@@ -47,17 +49,22 @@ This option makes sense only when used in combination with the - CURLOPT_SSL_VERIFYPEER(3) option. - - A specific error code (*CURLE_SSL_CRL_BADFILE*) is defined with the option. It --is returned when the SSL exchange fails because the CRL file cannot be --loaded. A failure in certificate verification due to a revocation information --found in the CRL does not trigger this specific error. -+is returned when the SSL exchange fails because the CRL file cannot be loaded. -+A failure in certificate verification due to a revocation information found in -+the CRL does not trigger this specific error. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -74,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CURLU.md b/docs/libcurl/opts/CURLOPT_CURLU.md -index 2bb1e73a9..f9a3020b3 100644 ---- a/docs/libcurl/opts/CURLOPT_CURLU.md -+++ b/docs/libcurl/opts/CURLOPT_CURLU.md -@@ -14,6 +14,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.63.0 - --- - - # NAME -@@ -44,7 +45,9 @@ updated contents is used. - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -68,9 +71,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.63.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md b/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md -index 62c8cf87c..886f27ce2 100644 ---- a/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md -+++ b/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md -@@ -15,6 +15,7 @@ Protocol: - - IMAP - - POP3 - - SMTP -+Added-in: 7.1 - --- - - # NAME -@@ -33,14 +34,18 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CUSTOMREQUEST, char *method); - - Pass a pointer to a null-terminated string as parameter. - --When changing the request *method* by setting CURLOPT_CUSTOMREQUEST(3), you --do not actually change how libcurl behaves or acts: you only change the actual -+When changing the request *method* by setting CURLOPT_CUSTOMREQUEST(3), you do -+not actually change how libcurl behaves or acts: you only change the actual - string sent in the request. - - libcurl passes on the verbatim string in its request without any filter or - other safe guards. That includes white space and control characters. - --Restore to the internal default by setting this to NULL. -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Restore to the internal default by setting this to NULL. - - This option can be used to specify the request: - -@@ -95,13 +100,12 @@ with CURLOPT_MAIL_RCPT(3), to specify an EXPN request. If the - CURLOPT_NOBODY(3) option is specified then the request can be used to - issue **NOOP** and **RSET** commands. - --The application does not have to keep the string around after setting this --option. -- - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -122,9 +126,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --IMAP is supported since 7.30.0, POP3 since 7.26.0 and SMTP since 7.34.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DEBUGDATA.md b/docs/libcurl/opts/CURLOPT_DEBUGDATA.md -index 0864388c2..3df122d6a 100644 ---- a/docs/libcurl/opts/CURLOPT_DEBUGDATA.md -+++ b/docs/libcurl/opts/CURLOPT_DEBUGDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_STDERR (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -33,6 +34,8 @@ not used by libcurl, it is only passed to the callback. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md b/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md -index a0927e202..4887f6272 100644 ---- a/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md -@@ -12,6 +12,7 @@ See-also: - - curl_global_trace (3) - Protocol: - - All -+Added-in: 7.9.6 - --- - - # NAME -@@ -91,16 +92,20 @@ The data is SSL/TLS (binary) data sent to the peer. - - The data is SSL/TLS (binary) data received from the peer. - --WARNING: This callback may be called with the curl *handle* set to an --internal handle. (Added in 8.4.0) -+## - --If you need to distinguish your curl *handle* from internal handles then --set CURLOPT_PRIVATE(3) on your handle. -+WARNING: This callback may be called with the curl *handle* set to an internal -+handle. (Added in 8.4.0) -+ -+If you need to distinguish your curl *handle* from internal handles then set -+CURLOPT_PRIVATE(3) on your handle. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -205,9 +210,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md b/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md -index 7da62e18a..9f85c6af0 100644 ---- a/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md -+++ b/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - All -+Added-in: 7.45.0 - --- - - # NAME -@@ -36,12 +37,12 @@ Use one of these protocol (scheme) names: - dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, pop3, - pop3s, rtsp, scp, sftp, smb, smbs, smtp, smtps, telnet, tftp - --An unknown or unsupported protocol causes error --*CURLE_UNSUPPORTED_PROTOCOL* when libcurl parses a URL without a --scheme. Parsing happens when curl_easy_perform(3) or --curl_multi_perform(3) is called. The protocol set supported by libcurl --vary depending on how it was built. Use curl_version_info(3) if you need --a list of protocol names supported by the build of libcurl that you are using. -+An unknown or unsupported protocol causes error *CURLE_UNSUPPORTED_PROTOCOL* -+when libcurl parses a URL without a scheme. Parsing happens when -+curl_easy_perform(3) or curl_multi_perform(3) is called. The protocol set -+supported by libcurl vary depending on how it was built. Use -+curl_version_info(3) if you need a list of protocol names supported by the -+build of libcurl that you are using. - - This option does not change the default proxy protocol (http). - -@@ -51,10 +52,15 @@ CURLOPT_URL(3) for details. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL (make a guess based on the host) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -74,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.45.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md b/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md -index 8775d16f1..1c5ee14c7 100644 ---- a/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md -+++ b/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md -@@ -11,6 +11,7 @@ Protocol: - - FTP - - SFTP - - POP3 -+Added-in: 7.17.0 - --- - - # NAME -@@ -36,6 +37,9 @@ messages on the POP3 server. This can be used to change the default behavior - of libcurl, when combined with a URL that contains a message ID, to perform a - "scan listing" which can then be used to determine the size of an email. - -+For FILE, this option has no effect yet as directories are always listed in -+this mode. -+ - Note: For FTP this causes a NLST command to be sent to the FTP server. Beware - that some FTP servers list only files in their response to NLST; they might - not include subdirectories and symbolic links. -@@ -50,6 +54,8 @@ effectively breaks that feature. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -70,11 +76,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - This option was known as CURLOPT_FTPLISTONLY up to 7.16.4. POP3 is supported - since 7.21.5. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md -index 788ef3018..66a5948bb 100644 ---- a/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md -+++ b/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md -@@ -5,12 +5,13 @@ Title: CURLOPT_DISALLOW_USERNAME_IN_URL - Section: 3 - Source: libcurl - See-also: -- - CURLOPT_PROTOCOLS (3) -+ - CURLOPT_PROTOCOLS_STR (3) - - CURLOPT_URL (3) - - curl_url_set (3) - - libcurl-security (3) - Protocol: - - All -+Added-in: 7.61.0 - --- - - # NAME -@@ -36,7 +37,9 @@ curl_url_set(3) function. - - # DEFAULT - --0 (disabled) - usernames are allowed by default. -+0 (disabled) -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.61.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md -index ca0c896e4..6ae904d65 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_RESOLVE (3) - Protocol: - - All -+Added-in: 7.9.3 - --- - - # NAME -@@ -54,6 +55,8 @@ Since version 8.1.0, libcurl prunes entries from the DNS cache if it exceeds - - 60 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md b/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md -index 20dc86edc..5e58e0fd0 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_INTERFACE (3) - Protocol: - - All -+Added-in: 7.33.0 - --- - - # NAME -@@ -35,10 +36,15 @@ specific interface). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,11 +61,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES -+ -+This option requires that libcurl was built with a resolver backend that -+supports this operation. The c-ares backend is the only such one. - --Added in 7.33.0. This option also requires that libcurl was built with a --resolver backend that supports this operation. The c-ares backend is the only --such one. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md -index 67a6bd204..046ddbcdb 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_DNS_SERVERS (3) - Protocol: - - All -+Added-in: 7.33.0 - --- - - # NAME -@@ -34,10 +35,15 @@ specific IP address). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,12 +60,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES - - This option requires that libcurl was built with a resolver backend that - supports this operation. The c-ares backend is the only such one. - --Added in 7.33.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md -index 332debd6b..e820ab11e 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_DNS_SERVERS (3) - Protocol: - - All -+Added-in: 7.33.0 - --- - - # NAME -@@ -34,10 +35,15 @@ address). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,12 +60,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES - - This option requires that libcurl was built with a resolver backend that - supports this operation. The c-ares backend is the only such one. - --Added in 7.33.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md b/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md -index 42874bd53..48a335230 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_DNS_LOCAL_IP6 (3) - Protocol: - - All -+Added-in: 7.24.0 - --- - - # NAME -@@ -29,18 +30,23 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_SERVERS, char *servers); - Pass a char pointer that is the list of DNS servers to be used instead of the - system default. The format of the dns servers option is: - --host[:port][,host[:port]]... -+ host[:port][,host[:port]]... - - For example: - --192.168.1.100,192.168.1.101,3.4.5.6 -+ 192.168.1.100,192.168.1.101,3.4.5.6 - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --NULL - use system default -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -59,12 +65,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES - - This option requires that libcurl was built with a resolver backend that - supports this operation. The c-ares backend is the only such one. - --Added in 7.24.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md b/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md -index 33dcb0f06..2074fff87 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_IPRESOLVE (3) - Protocol: - - All -+Added-in: 7.60.0 - --- - - # NAME -@@ -46,6 +47,8 @@ performance impacts and may cause IPv4 to be used before IPv6 or vice versa. - - 0 (disabled) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.60.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md b/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md -index 616ddb951..20670db00 100644 ---- a/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md -+++ b/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_SHARE (3) - Protocol: - - All -+Added-in: 7.9.3 - --- - - # NAME -@@ -26,7 +27,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_DNS_USE_GLOBAL_CACHE, - - # DESCRIPTION - --Has no function since 7.62.0. Do not use! -+Has no function since 7.62.0. Do not use. - - Pass a long. If the *enable* value is 1, it tells curl to use a global DNS - cache that survives between easy handle creations and deletions. This is not -@@ -39,6 +40,8 @@ cache between transfers. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,11 @@ int main(void) - - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.11.1. Functionality removed in 7.62.0. - --Deprecated since 7.11.1. Function removed in 7.62.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md -index 4211f03cb..95227616c 100644 ---- a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md -+++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md -@@ -14,6 +14,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.76.0 - --- - - # NAME -@@ -50,7 +51,7 @@ for consistency with the other *VERIFYHOST* options we suggest use 2 and - not 1. - - When the *verify* value is set to 0L, the connection succeeds regardless of --the names used in the certificate. Use that ability with caution! -+the names used in the certificate. Use that ability with caution. - - See also CURLOPT_DOH_SSL_VERIFYPEER(3) to verify the digital signature - of the DoH server certificate. -@@ -59,6 +60,8 @@ of the DoH server certificate. - - 2 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -79,11 +82,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.76.0 -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md -index b35fa5272..e8674e06f 100644 ---- a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md -+++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md -@@ -16,6 +16,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.76.0 - --- - - # NAME -@@ -71,6 +72,8 @@ the correct end-point. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -91,11 +94,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.76.0 -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md -index 8135cb4c7..fb861ae74 100644 ---- a/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md -+++ b/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.76.0 - --- - - # NAME -@@ -46,6 +47,8 @@ the verification fails. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.76.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_DOH_URL.md b/docs/libcurl/opts/CURLOPT_DOH_URL.md -index d382ca67d..cf7a04e19 100644 ---- a/docs/libcurl/opts/CURLOPT_DOH_URL.md -+++ b/docs/libcurl/opts/CURLOPT_DOH_URL.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_VERBOSE (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -40,7 +41,11 @@ To find the DoH server itself, which might be specified using a name, libcurl - uses the default name lookup function. You can bootstrap that by providing the - address for the DoH server with CURLOPT_RESOLVE(3). - --Disable DoH use again by setting this option to NULL. -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. - - # INHERIT OPTIONS - -@@ -63,8 +68,9 @@ CURLOPT_FTPPORT(3), a proxy type set to **CURLPROXY_SOCKS4** or - - # DEFAULT - --NULL - there is no default DoH URL. If this option is not set, libcurl uses --the default name resolver. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -80,9 +86,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ECH.md b/docs/libcurl/opts/CURLOPT_ECH.md -new file mode 100644 -index 000000000..b8251fe18 ---- /dev/null -+++ b/docs/libcurl/opts/CURLOPT_ECH.md -@@ -0,0 +1,108 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Title: CURLOPT_ECH -+Section: 3 -+Source: libcurl -+See-also: -+ - CURLOPT_DOH_URL (3) -+Protocol: -+ - TLS -+TLS-backend: -+ - OpenSSL -+ - wolfSSL -+Added-in: 8.8.0 -+--- -+ -+# NAME -+ -+CURLOPT_ECH - configuration for Encrypted Client Hello -+ -+# SYNOPSIS -+ -+~~~c -+#include -+ -+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ECH, char *config); -+~~~ -+ -+# DESCRIPTION -+ -+ECH is only compatible with TLSv1.3. -+ -+This experimental feature requires a special build of OpenSSL, as ECH is not -+yet supported in OpenSSL releases. In contrast ECH is supported by the latest -+BoringSSL and wolfSSL releases. -+ -+There is also a known issue with using wolfSSL which does not support ECH when -+the HelloRetryRequest mechanism is used. -+ -+Pass a string that specifies configuration details for ECH. In all cases, if -+ECH is attempted, it may fail for various reasons. The keywords supported are: -+ -+## false -+ -+Turns off ECH. -+ -+## grease -+ -+Instructs client to emit a GREASE ECH extension. (The connection fails if ECH -+is attempted but fails.) -+ -+## true -+ -+Instructs client to attempt ECH, if possible, but to not fail if attempting -+ECH is not possible. -+ -+## hard -+ -+Instructs client to attempt ECH and fail if attempting ECH is not possible. -+ -+## ecl:\ -+ -+If the string starts with `ecl:` then the remainder of the string should be a -+base64-encoded ECHConfigList that is used for ECH rather than attempting to -+download such a value from the DNS. -+ -+## pn:\ -+ -+If the string starts with `pn:` then the remainder of the string should be a -+DNS/hostname that is used to over-ride the public_name field of the -+ECHConfigList that is used for ECH. -+ -+## -+ -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL or "false" to disable its use again. -+ -+# DEFAULT -+ -+NULL, meaning ECH is disabled. -+ -+# %PROTOCOLS% -+ -+# EXAMPLE -+ -+~~~c -+int main(void) -+{ -+ CURL *curl = curl_easy_init(); -+ -+ const char *config = \ -+ "ecl:AED+DQA87wAgACB/RuzUCsW3uBbSFI7mzD63TUXpI8sGDTnFTbFCDpa+" \ -+ "CAAEAAEAAQANY292ZXIuZGVmby5pZQAA"; -+ if(curl) { -+ curl_easy_setopt(curl, CURLOPT_ECH, config); -+ curl_easy_perform(curl); -+ } -+} -+~~~ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient -+heap space. -diff --git a/docs/libcurl/opts/CURLOPT_EGDSOCKET.md b/docs/libcurl/opts/CURLOPT_EGDSOCKET.md -index 32ae012e5..05fb76ed0 100644 ---- a/docs/libcurl/opts/CURLOPT_EGDSOCKET.md -+++ b/docs/libcurl/opts/CURLOPT_EGDSOCKET.md -@@ -10,6 +10,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.7 - --- - - # NAME -@@ -28,39 +29,16 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_EGDSOCKET, char *path); - - Deprecated option. It serves no purpose anymore. - --Pass a char pointer to the null-terminated path name to the Entropy Gathering --Daemon socket. It is used to seed the random engine for TLS. -- --The application does not have to keep the string around after setting this --option. -- - # DEFAULT - - NULL - --# EXAMPLE -- --~~~c --int main(void) --{ -- CURL *curl = curl_easy_init(); -- if(curl) { -- CURLcode res; -- curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- curl_easy_setopt(curl, CURLOPT_EGDSOCKET, "/var/egd.socket"); -- res = curl_easy_perform(curl); -- curl_easy_cleanup(curl); -- } --} --~~~ -- --# AVAILABILITY -- --Only with OpenSSL versions before 1.1.0. -+# DEPRECATED - - This option was deprecated in 7.84.0. - -+# %AVAILABILITY% -+ - # RETURN VALUE - --Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or --CURLE_OUT_OF_MEMORY if there was insufficient heap space. -+Returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md b/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md -index 7a90f1d6c..edac39b95 100644 ---- a/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md -+++ b/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md -@@ -13,6 +13,7 @@ See-also: - - curl_url_strerror (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -36,21 +37,26 @@ be at least **CURL_ERROR_SIZE** bytes big. - - You must keep the associated buffer available until libcurl no longer needs - it. Failing to do so might cause odd behavior or even crashes. libcurl might --need it until you call curl_easy_cleanup(3) or you set the same option --again to use a different pointer. -+need it until you call curl_easy_cleanup(3) or you set the same option again -+to use a different pointer. - - Do not rely on the contents of the buffer unless an error code was returned. - Since 7.60.0 libcurl initializes the contents of the error buffer to an empty - string before performing the transfer. For earlier versions if an error code - was returned but there was no error detail then the buffer was untouched. - --Consider CURLOPT_VERBOSE(3) and CURLOPT_DEBUGFUNCTION(3) to better --debug and trace why errors happen. -+Consider CURLOPT_VERBOSE(3) and CURLOPT_DEBUGFUNCTION(3) to better debug and -+trace why errors happen. -+ -+Using this option multiple times makes the last set pointer override the -+previous ones. Set it to NULL to disable its use again. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -90,9 +96,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md -index 7f6f274b4..45997dcc1 100644 ---- a/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_POST (3) - Protocol: - - HTTP -+Added-in: 7.36.0 - --- - - # NAME -@@ -36,6 +37,8 @@ sent anyway. - - 1000 milliseconds - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.36.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FAILONERROR.md b/docs/libcurl/opts/CURLOPT_FAILONERROR.md -index aabee4e4d..d865b637c 100644 ---- a/docs/libcurl/opts/CURLOPT_FAILONERROR.md -+++ b/docs/libcurl/opts/CURLOPT_FAILONERROR.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_KEEP_SENDING_ON_ERROR (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -45,6 +46,8 @@ get closed and *CURLE_HTTP_RETURNED_ERROR* is returned. - - 0, do not fail on error - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -63,9 +66,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FILETIME.md b/docs/libcurl/opts/CURLOPT_FILETIME.md -index 1f4782e3e..bca79ab90 100644 ---- a/docs/libcurl/opts/CURLOPT_FILETIME.md -+++ b/docs/libcurl/opts/CURLOPT_FILETIME.md -@@ -13,6 +13,7 @@ Protocol: - - SFTP - - FILE - - SMB -+Added-in: 7.5 - --- - - # NAME -@@ -39,6 +40,8 @@ transfer to extract the received time (if any). - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always, for SFTP since 7.49.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md b/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md -index 33dce7b0c..866333f14 100644 ---- a/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md -+++ b/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WILDCARDMATCH (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -33,6 +34,8 @@ the CURLOPT_FNMATCH_FUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md b/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md -index 16526931e..f9ff1d3b2 100644 ---- a/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_WILDCARDMATCH (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -44,6 +45,8 @@ error occurred. - - NULL == an internal function for wildcard matching. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -77,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md b/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md -index 9dee48bef..4bd02eea0 100644 ---- a/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md -+++ b/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md -@@ -8,10 +8,12 @@ See-also: - - CURLINFO_REDIRECT_COUNT (3) - - CURLINFO_REDIRECT_URL (3) - - CURLOPT_POSTREDIR (3) -- - CURLOPT_PROTOCOLS (3) -- - CURLOPT_REDIR_PROTOCOLS (3) -+ - CURLOPT_PROTOCOLS_STR (3) -+ - CURLOPT_REDIR_PROTOCOLS_STR (3) -+ - CURLOPT_UNRESTRICTED_AUTH (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -33,38 +35,49 @@ redirects that an HTTP server sends in a 30x response. The Location: header - can specify a relative or an absolute URL to follow. - - libcurl issues another request for the new URL and follows subsequent new --Location: redirects all the way until no more such headers are returned or the --maximum limit is reached. CURLOPT_MAXREDIRS(3) is used to limit the --number of redirects libcurl follows. -+`Location:` redirects all the way until no more such headers are returned or -+the maximum limit is reached. CURLOPT_MAXREDIRS(3) is used to limit the number -+of redirects libcurl follows. - - libcurl restricts what protocols it automatically follow redirects to. The --accepted target protocols are set with CURLOPT_REDIR_PROTOCOLS(3). By -+accepted target protocols are set with CURLOPT_REDIR_PROTOCOLS_STR(3). By - default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects. - - When following a redirect, the specific 30x response code also dictates which - request method libcurl uses in the subsequent request: For 301, 302 and 303 --responses libcurl switches method from POST to GET unless --CURLOPT_POSTREDIR(3) instructs libcurl otherwise. All other redirect --response codes make libcurl use the same method again. -+responses libcurl switches method from POST to GET unless CURLOPT_POSTREDIR(3) -+instructs libcurl otherwise. All other redirect response codes make libcurl -+use the same method again. - - For users who think the existing location following is too naive, too simple - or just lacks features, it is easy to instead implement your own redirect --follow logic with the use of curl_easy_getinfo(3)'s --CURLINFO_REDIRECT_URL(3) option instead of using --CURLOPT_FOLLOWLOCATION(3). -+follow logic with the use of curl_easy_getinfo(3)'s CURLINFO_REDIRECT_URL(3) -+option instead of using CURLOPT_FOLLOWLOCATION(3). -+ -+By default, libcurl only sends `Authentication:` or explicitly set `Cookie:` -+headers to the initial host given in the original URL, to avoid leaking -+username + password to other sites. CURLOPT_UNRESTRICTED_AUTH(3) is provided -+to change that behavior. -+ -+Due to the way HTTP works, almost any header can be made to contain data a -+client may not want to pass on to other servers than the initially intended -+host and for all other headers than the two mentioned above, there is no -+protection from this happening when libcurl is told to follow redirects. - - # NOTE - - Since libcurl changes method or not based on the specific HTTP response code, --setting CURLOPT_CUSTOMREQUEST(3) while following redirects may change --what libcurl would otherwise do and if not that carefully may even make it --misbehave since CURLOPT_CUSTOMREQUEST(3) overrides the method libcurl --would otherwise select internally. -+setting CURLOPT_CUSTOMREQUEST(3) while following redirects may change what -+libcurl would otherwise do and if not that carefully may even make it -+misbehave since CURLOPT_CUSTOMREQUEST(3) overrides the method libcurl would -+otherwise select internally. - - # DEFAULT - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -82,9 +95,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md b/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md -index bbd1c48f7..2f452ff59 100644 ---- a/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md -+++ b/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_MAXLIFETIME_CONN (3) - Protocol: - - All -+Added-in: 7.7 - --- - - # NAME -@@ -39,6 +40,8 @@ Set to 0 to have libcurl keep the connection open for possible later reuse - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md b/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md -index f7ffbe89a..f64c6adc7 100644 ---- a/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md -+++ b/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_FORBID_REUSE (3) - - CURLOPT_MAXAGE_CONN (3) - - CURLOPT_MAXLIFETIME_CONN (3) -+Added-in: 7.7 - --- - - # NAME -@@ -41,6 +42,8 @@ Set *fresh* to 0 to have libcurl attempt reusing an existing connection - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTPPORT.md b/docs/libcurl/opts/CURLOPT_FTPPORT.md -index 869a862f9..7f82b1794 100644 ---- a/docs/libcurl/opts/CURLOPT_FTPPORT.md -+++ b/docs/libcurl/opts/CURLOPT_FTPPORT.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTP_USE_EPRT (3) - - CURLOPT_FTP_USE_EPSV (3) -+Added-in: 7.1 - --- - - # NAME -@@ -45,12 +46,10 @@ specifier can be in brackets. - - Examples with specified ports: - --~~~c -- eth0:0 -- 192.168.1.2:32000-33000 -- curl.se:32123 -- [::1]:1234-4567 --~~~ -+ eth0:0 -+ 192.168.1.2:32000-33000 -+ curl.se:32123 -+ [::1]:1234-4567 - - We strongly advise against specifying the address with a name, as it causes - libcurl to do a blocking name resolve call to retrieve the IP address. That -@@ -60,16 +59,19 @@ CURLOPT_DOH_URL(3) is set. - Using anything else than "-" for this option should typically only be done if - you have special knowledge and confirmation that it works. - --You disable PORT again and go back to using the passive version by setting --this option to NULL. -- - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. You disable PORT again and go back to using the passive version -+by setting this option to NULL. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -87,9 +89,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Port range support was added in 7.19.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md b/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md -index d40c75fe4..5e1300dd6 100644 ---- a/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md -+++ b/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTP_SSL_CCC (3) - - CURLOPT_USE_SSL (3) -+Added-in: 7.12.2 - --- - - # NAME -@@ -47,6 +48,8 @@ Try "AUTH TLS" first, and only if that fails try "AUTH SSL". - - CURLFTPAUTH_DEFAULT - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.12.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md b/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md -index de6b2a50e..aae893d30 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_PASSWORD (3) - - CURLOPT_USERNAME (3) -+Added-in: 7.13.0 - --- - - # NAME -@@ -32,10 +33,15 @@ this data is sent off using the ACCT command. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.13.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md b/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md -index 7d334f545..54fd80b6e 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_FTP_SKIP_PASV_IP (3) - - CURLOPT_SERVER_RESPONSE_TIMEOUT (3) - - CURLOPT_USERNAME (3) -+Added-in: 7.15.5 - --- - - # NAME -@@ -41,6 +42,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md b/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md -index 5a6dbf696..f428243ca 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTP_FILEMETHOD (3) - - CURLOPT_FTP_USE_EPSV (3) -+Added-in: 7.10.7 - --- - - # NAME -@@ -49,12 +50,14 @@ retry the CWD command again if the subsequent **MKD** command fails. This is - especially useful if you are doing many simultaneous connections against the - same server and they all have this option enabled, as then CWD may first fail - but then another connection does **MKD** before this connection and thus --**MKD** fails but trying CWD works! -+**MKD** fails but trying CWD works. - - # DEFAULT - - CURLFTP_CREATE_DIR_NONE (0) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,10 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.7. SFTP support added in 7.16.3. The retry option was added in --7.19.4. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md b/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md -index 351dfe10e..342f72f7c 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_DIRLISTONLY (3) - - CURLOPT_FTP_SKIP_PASV_IP (3) -+Added-in: 7.15.1 - --- - - # NAME -@@ -56,6 +57,8 @@ compliant than 'nocwd' but without the full penalty of 'multicwd'. - - CURLFTPMETHOD_MULTICWD - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md -index cdec3371b..65f88192a 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTPPORT (3) - - CURLOPT_FTP_USE_EPRT (3) -+Added-in: 7.15.0 - --- - - # NAME -@@ -42,6 +43,8 @@ This option has no effect if PORT, EPRT or EPSV is used instead of PASV. - - 1 since 7.74.0, was 0 before then. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.14.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md b/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md -index 6155c4aed..ccccc8c21 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_FTPSSLAUTH (3) - - CURLOPT_PROTOCOLS_STR (3) - - CURLOPT_USE_SSL (3) -+Added-in: 7.16.1 - --- - - # NAME -@@ -49,6 +50,8 @@ Initiate the shutdown and wait for a reply. - - CURLFTPSSL_CCC_NONE - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md b/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md -index 54df92573..c651fe949 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTPPORT (3) - - CURLOPT_FTP_USE_EPSV (3) -+Added-in: 7.10.5 - --- - - # NAME -@@ -41,6 +42,8 @@ then. - - # DEFAULT - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md b/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md -index 41d8f9ed0..8b8051fd8 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_FTPPORT (3) - - CURLOPT_FTP_USE_EPRT (3) -+Added-in: 7.9.2 - --- - - # NAME -@@ -41,6 +42,8 @@ If the server is an IPv6 host, this option has no effect. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with FTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md b/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md -index 1d9507c78..d50be758a 100644 ---- a/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md -+++ b/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_FTP_USE_EPSV (3) - Protocol: - - FTP -+Added-in: 7.20.0 - --- - - # NAME -@@ -34,6 +35,8 @@ no effect when using the active FTP transfers mode. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -45,7 +48,7 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_URL, - "ftp://example.com/old-server/file.txt"); - -- /* a drftpd server, do it! */ -+ /* a drftpd server, do it */ - curl_easy_setopt(curl, CURLOPT_FTP_USE_PRET, 1L); - - res = curl_easy_perform(curl); -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md b/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md -index 01bf42d17..e60b503b7 100644 ---- a/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md -+++ b/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_HTTPAUTH (3) - - CURLOPT_PROXYAUTH (3) -+Added-in: 7.22.0 - --- - - # NAME -@@ -37,6 +38,8 @@ available at compile-time. - - CURLGSSAPI_DELEGATION_NONE - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.22.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md -index 5f51f9422..f13abddbd 100644 ---- a/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_CONNECTTIMEOUT_MS (3) - - CURLOPT_LOW_SPEED_LIMIT (3) - - CURLOPT_TIMEOUT (3) -+Added-in: 7.59.0 - --- - - # NAME -@@ -42,6 +43,8 @@ currently defaults to 200 ms. Firefox and Chrome currently default to 300 ms. - - CURL_HET_DEFAULT (currently defined as 200L) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.59.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md b/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md -index da4f35ce5..99e7fce58 100644 ---- a/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md -+++ b/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_PROXY (3) - Protocol: - - All -+Added-in: 7.60.0 - --- - - # NAME -@@ -38,6 +39,8 @@ Most applications do not need this option. - - 0, do not send any HAProxy PROXY protocol header - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP. Added in 7.60.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md b/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md -index fdb16fe64..fb0f0ec52 100644 ---- a/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md -+++ b/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_HAPROXYPROTOCOL (3) - - CURLOPT_PROXY (3) -+Added-in: 8.2.0 - --- - - # NAME -@@ -30,13 +31,21 @@ When this parameter is set to a valid IPv4 or IPv6 numerical address, the - library sends this address as client address in the HAProxy PROXY protocol v1 - header at beginning of the connection. - --This option is an alternative to CURLOPT_HAPROXYPROTOCOL(3) as that one --cannot use a specified address. -+This option is an alternative to CURLOPT_HAPROXYPROTOCOL(3) as that one cannot -+use a specified address. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+The application does not have to keep the string around after setting this -+option. - - # DEFAULT - - NULL, no HAProxy header is sent - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -52,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP. Added in 8.2.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HEADER.md b/docs/libcurl/opts/CURLOPT_HEADER.md -index 09262f697..fd81b37c8 100644 ---- a/docs/libcurl/opts/CURLOPT_HEADER.md -+++ b/docs/libcurl/opts/CURLOPT_HEADER.md -@@ -13,6 +13,7 @@ Protocol: - See-also: - - CURLOPT_HEADERFUNCTION (3) - - CURLOPT_HTTPHEADER (3) -+Added-in: 7.1 - --- - - # NAME -@@ -47,12 +48,14 @@ It is often better to use CURLOPT_HEADERFUNCTION(3) to get the header - data separately. - - While named confusingly similar, CURLOPT_HTTPHEADER(3) is used to set --custom HTTP headers! -+custom HTTP headers. - - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Provided in all libcurl versions. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HEADERDATA.md b/docs/libcurl/opts/CURLOPT_HEADERDATA.md -index 84d232eb8..0542e158f 100644 ---- a/docs/libcurl/opts/CURLOPT_HEADERDATA.md -+++ b/docs/libcurl/opts/CURLOPT_HEADERDATA.md -@@ -10,6 +10,7 @@ See-also: - - curl_easy_header (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME -@@ -35,7 +36,7 @@ If CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) is used, - If neither of those options are set, *pointer* must be a valid FILE * and - it is used by a plain fwrite() to write headers to. - --If you are using libcurl as a win32 DLL, you **MUST** use a -+If you are using libcurl as a Windows DLL, you **MUST** use a - CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set - this option or you might experience crashes. - -@@ -43,6 +44,8 @@ this option or you might experience crashes. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md -index 6668c82c2..3c7e0a9e5 100644 ---- a/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md -@@ -14,6 +14,7 @@ Protocol: - - POP3 - - IMAP - - SMTP -+Added-in: 7.7.2 - --- - - # NAME -@@ -42,12 +43,12 @@ shown above. - This callback function gets invoked by libcurl as soon as it has received - header data. The header callback is called once for each header and only - complete header lines are passed on to the callback. Parsing headers is easy --to do using this callback. *buffer* points to the delivered data, and the --size of that data is *nitems*; *size* is always 1. The provide header --line is not null-terminated! -+to do using this callback. *buffer* points to the delivered data, and the size -+of that data is *nitems*; *size* is always 1. The provided header line is not -+null-terminated. Do not modify the passed in buffer. - --The pointer named *userdata* is the one you set with the --CURLOPT_HEADERDATA(3) option. -+The pointer named *userdata* is the one you set with the CURLOPT_HEADERDATA(3) -+option. - - Your callback should return the number of bytes actually taken care of. If - that amount differs from the amount passed to your callback function, it -@@ -100,6 +101,8 @@ although strictly they are just continuations of the previous lines. - - Nothing. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -124,9 +127,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HEADEROPT.md b/docs/libcurl/opts/CURLOPT_HEADEROPT.md -index 833fda063..9c74c6fa5 100644 ---- a/docs/libcurl/opts/CURLOPT_HEADEROPT.md -+++ b/docs/libcurl/opts/CURLOPT_HEADEROPT.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_HTTPHEADER (3) - - CURLOPT_PROXYHEADER (3) -+Added-in: 7.37.0 - --- - - # NAME -@@ -44,6 +45,8 @@ proxy and then CURLOPT_HTTPHEADER(3) headers only to the server. - - CURLHEADER_SEPARATE (changed in 7.42.1, used CURLHEADER_UNIFIED before then) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,7 +64,7 @@ int main(void) - - /* HTTPS over a proxy makes a separate CONNECT to the proxy, so tell - libcurl to not send the custom headers to the proxy. Keep them -- separate! */ -+ separate. */ - curl_easy_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE); - ret = curl_easy_perform(curl); - curl_slist_free_all(list); -@@ -70,9 +73,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.37.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTS.md b/docs/libcurl/opts/CURLOPT_HSTS.md -index b71476e5b..3d5f957a8 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTS.md -+++ b/docs/libcurl/opts/CURLOPT_HSTS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_ALTSVC (3) - - CURLOPT_HSTS_CTRL (3) - - CURLOPT_RESOLVE (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -32,8 +33,9 @@ name with this option also enables HSTS for this handle (the equivalent of - setting *CURLHSTS_ENABLE* with CURLOPT_HSTS_CTRL(3)). - - If the given file does not exist or contains no HSTS entries at startup, the --HSTS cache simply starts empty. Setting the filename to NULL or "" only --enables HSTS without reading from or writing to any file. -+HSTS cache simply starts empty. Setting the filename to NULL allows HSTS -+without reading from or writing to any file. NULL also makes libcurl clear the -+list of files to read HSTS data from, if any such were previously set. - - If this option is set multiple times, libcurl loads cache entries from each - given file but only stores the last used name for later writing. -@@ -43,7 +45,7 @@ given file but only stores the last used name for later writing. - The HSTS cache is saved to and loaded from a text file with one entry per - physical line. Each line in the file has the following format: - --[host] [stamp] -+ [host] [stamp] - - [host] is the domain name for the entry and the name is dot-prefixed if it is - an entry valid for all subdomains to the name as well or only for the exact -@@ -59,6 +61,8 @@ currently no length or size limit. - - NULL, no filename - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -72,9 +76,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md b/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md -index 8c3230982..eda180e30 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md -+++ b/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_HSTSREADFUNCTION (3) - - CURLOPT_HSTSWRITEDATA (3) - - CURLOPT_HSTSWRITEFUNCTION (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -38,6 +39,8 @@ do that. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md b/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md -index fe55ab8de..5d03607fa 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_HSTSREADDATA (3) - - CURLOPT_HSTSWRITEFUNCTION (3) - - CURLOPT_HSTS_CTRL (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -63,6 +64,8 @@ do that. - - NULL - no callback. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -95,9 +98,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md b/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md -index 23c7302f0..6be5582db 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md -+++ b/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_HSTSREADDATA (3) - - CURLOPT_HSTSREADFUNCTION (3) - - CURLOPT_HSTSWRITEFUNCTION (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -38,6 +39,8 @@ do that. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md -index 8fa621510..621268ea5 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_HSTSWRITEDATA (3) - - CURLOPT_HSTSWRITEFUNCTION (3) - - CURLOPT_HSTS_CTRL (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -67,6 +68,8 @@ do that. - - NULL - no callback. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -99,9 +102,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md b/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md -index dec7a3844..8dee60867 100644 ---- a/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md -+++ b/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_CONNECT_TO (3) - - CURLOPT_HSTS (3) - - CURLOPT_RESOLVE (3) -+Added-in: 7.74.0 - --- - - # NAME -@@ -52,7 +53,9 @@ to the file when closing the handle. - - # DEFAULT - --0. HSTS is disabled by default. -+0 -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.74.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md b/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md -index 6312148c2..56c177cfa 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md -+++ b/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_HTTP_VERSION (3) - - CURLOPT_SSLVERSION (3) -+Added-in: 7.64.0 - --- - - # NAME -@@ -29,14 +30,13 @@ Pass the long argument *allowed* set to 1L to allow HTTP/0.9 responses. - - An HTTP/0.9 response is a server response entirely without headers and only a - body. You can connect to lots of random TCP services and still get a response --that curl might consider to be HTTP/0.9! -+that curl might consider to be HTTP/0.9. - - # DEFAULT - --curl allowed HTTP/0.9 responses by default before 7.66.0 -+0 - --Since 7.66.0, libcurl requires this option set to 1L to allow HTTP/0.9 --responses. -+# %PROTOCOLS% - - # EXAMPLE - -@@ -53,9 +53,14 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+curl allowed HTTP/0.9 responses by default before 7.66.0 -+ -+Since 7.66.0, libcurl requires this option set to 1L to allow HTTP/0.9 -+responses. - --Option added in 7.64.0, present along with HTTP. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md b/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md -index 4363ef444..933ed135b 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md -+++ b/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_HTTP09_ALLOWED (3) - - CURLOPT_HTTP_VERSION (3) -+Added-in: 7.10.3 - --- - - # NAME -@@ -40,10 +41,18 @@ curl_slist_free_all(3) to clean up an entire list. - The alias itself is not parsed for any version strings. The protocol is - assumed to match HTTP 1.0 when an alias match. - -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +73,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTPAUTH.md b/docs/libcurl/opts/CURLOPT_HTTPAUTH.md -index 9e29f7cae..e436e078c 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTPAUTH.md -+++ b/docs/libcurl/opts/CURLOPT_HTTPAUTH.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PASSWORD (3) - - CURLOPT_PROXYAUTH (3) - - CURLOPT_USERNAME (3) -+Added-in: 7.10.6 - --- - - # NAME -@@ -84,6 +85,8 @@ option to work, or build libcurl on Windows with SSPI support. - - ## CURLAUTH_NTLM_WB - -+Support for this is removed since libcurl 8.8.0. -+ - NTLM delegating to winbind helper. Authentication is performed by a separate - binary application that is executed when needed. The name of the application - is specified at compile time but is typically **/usr/bin/ntlm_auth**. -@@ -123,6 +126,8 @@ see CURLOPT_AWS_SIGV4(3). - - CURLAUTH_BASIC - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -140,9 +145,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Option Added in 7.10.6. -+# HISTORY - - CURLAUTH_DIGEST_IE was added in 7.19.3 - -@@ -154,6 +157,8 @@ CURLAUTH_BEARER was added in 7.61.0 - - CURLAUTH_AWS_SIGV4 was added in 7.74.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_HTTPGET.md b/docs/libcurl/opts/CURLOPT_HTTPGET.md -index 8f5c35463..109fe9ce4 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTPGET.md -+++ b/docs/libcurl/opts/CURLOPT_HTTPGET.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_POST (3) - - CURLOPT_UPLOAD (3) - - curl_easy_reset (3) -+Added-in: 7.8.1 - --- - - # NAME -@@ -42,6 +43,8 @@ reset a handle to default method, consider curl_easy_reset(3). - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md -index 7f060ea89..cd49b1b89 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTPHEADER.md -+++ b/docs/libcurl/opts/CURLOPT_HTTPHEADER.md -@@ -15,6 +15,7 @@ See-also: - - CURLOPT_MIMEPOST (3) - - CURLOPT_PROXYHEADER (3) - - curl_mime_init (3) -+Added-in: 7.1 - --- - - # NAME -@@ -34,23 +35,22 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_HTTPHEADER, - - Pass a pointer to a linked list of HTTP headers to pass to the server and/or - proxy in your HTTP request. The same list can be used for both host and proxy --requests! -+requests. - - When used within an IMAP or SMTP request to upload a MIME mail, the given - header list establishes the document-level MIME headers to prepend to the --uploaded document described by CURLOPT_MIMEPOST(3). This does not affect --raw mail uploads. -- --The linked list should be a fully valid list of **struct curl_slist** --structs properly filled in. Use curl_slist_append(3) to create the list --and curl_slist_free_all(3) to clean up an entire list. If you add a --header that is otherwise generated and used by libcurl internally, your added --header is used instead. If you add a header with no content as in 'Accept:' --(no data on the right side of the colon), the internally used header is --disabled/removed. With this option you can add new headers, replace internal --headers and remove internal headers. To add a header with no content (nothing --to the right side of the colon), use the form 'name;' (note the ending --semicolon). -+uploaded document described by CURLOPT_MIMEPOST(3). This does not affect raw -+mail uploads. -+ -+The linked list should be a fully valid list of **struct curl_slist** structs -+properly filled in. Use curl_slist_append(3) to create the list and -+curl_slist_free_all(3) to clean up an entire list. If you add a header that is -+otherwise generated and used by libcurl internally, your added header is used -+instead. If you add a header with no content as in 'Accept:' (no data on the -+right side of the colon), the internally used header is disabled/removed. With -+this option you can add new headers, replace internal headers and remove -+internal headers. To add a header with no content (nothing to the right side -+of the colon), use the form 'name;' (note the ending semicolon). - - The headers included in the linked list **must not** be CRLF-terminated, - because libcurl adds CRLF after each header item itself. Failure to comply -@@ -64,16 +64,16 @@ following the request-line are headers. Adding this method line in this list - of headers only causes your request to send an invalid header. Use - CURLOPT_CUSTOMREQUEST(3) to change the method. - --When this option is passed to curl_easy_setopt(3), libcurl does not copy --the entire list so you **must** keep it around until you no longer use this --*handle* for a transfer before you call curl_slist_free_all(3) on --the list. -+When this option is passed to curl_easy_setopt(3), libcurl does not copy the -+entire list so you **must** keep it around until you no longer use this -+*handle* for a transfer before you call curl_slist_free_all(3) on the list. - --Pass a NULL to this option to reset back to no custom headers. -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. - - The most commonly replaced HTTP headers have "shortcuts" in the options --CURLOPT_COOKIE(3), CURLOPT_USERAGENT(3) and --CURLOPT_REFERER(3). We recommend using those. -+CURLOPT_COOKIE(3), CURLOPT_USERAGENT(3) and CURLOPT_REFERER(3). We recommend -+using those. - - There is an alternative option that sets or replaces headers only for requests - that are sent with CONNECT to a proxy: CURLOPT_PROXYHEADER(3). Use -@@ -114,9 +114,11 @@ MIME mail is only composed of alternative representations of the same data - In all cases the value must be of the form "multipart/*" to respect the - document structure and may not include the "boundary=" parameter. - -+## -+ - Other specific headers that do not have a libcurl default value but are - strongly desired by mail delivery and user agents should also be included. --These are "From:", "To:", "Date:" and "Subject:" among others and their -+These are `From:`, `To:`, `Date:` and `Subject:` among others and their - presence and value is generally checked by anti-spam utilities. - - # SECURITY CONCERNS -@@ -148,6 +150,8 @@ with the CURLOPT_UNRESTRICTED_AUTH(3) option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -172,9 +176,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Use for MIME mail added in 7.56.0. - --As long as HTTP is enabled. Use in MIME mail added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTPPOST.md b/docs/libcurl/opts/CURLOPT_HTTPPOST.md -index 0c3947147..e9381c376 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTPPOST.md -+++ b/docs/libcurl/opts/CURLOPT_HTTPPOST.md -@@ -13,6 +13,7 @@ See-also: - - curl_formadd (3) - - curl_formfree (3) - - curl_mime_init (3) -+Added-in: 7.1 - --- - - # NAME -@@ -49,6 +50,8 @@ CURLOPT_NOBODY(3) to 0. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -89,9 +92,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated in 7.56.0. - --As long as HTTP is enabled. Deprecated in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md b/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md -index 9591892df..60b4e6a80 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md -+++ b/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PROXY (3) - - CURLOPT_PROXYPORT (3) - - CURLOPT_PROXYTYPE (3) -+Added-in: 7.3 - --- - - # NAME -@@ -49,6 +50,8 @@ rarely works through the proxy anyway). - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md b/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md -index 10ff5ab4d..3c3e381ac 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md -+++ b/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_ACCEPT_ENCODING (3) - - CURLOPT_DEBUGFUNCTION (3) - - CURLOPT_STDERR (3) -+Added-in: 7.16.2 - --- - - # NAME -@@ -36,6 +37,8 @@ CURLOPT_ACCEPT_ENCODING(3) for that. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md b/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md -index c0b88b83f..52cee575b 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md -+++ b/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_ACCEPT_ENCODING (3) - - CURLOPT_HTTP_CONTENT_DECODING (3) -+Added-in: 7.16.2 - --- - - # NAME -@@ -30,10 +31,17 @@ Pass a long to tell libcurl how to act on transfer decoding. If set to zero, - transfer decoding is disabled, if set to 1 it is enabled (default). libcurl - does chunked transfer decoding by default unless this option is set to zero. - -+# NOTES -+ -+This option does not work with the hyper backend as that always has transfer -+decoding enabled. -+ - # DEFAULT - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -49,10 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.2 Does not work with the hyper backend (it always has transfer --decoding enabled). -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md -index 88a7154b9..32c2c2ce6 100644 ---- a/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md -+++ b/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_HTTP09_ALLOWED (3) - - CURLOPT_HTTP200ALIASES (3) - - CURLOPT_SSLVERSION (3) -+Added-in: 7.9.1 - --- - - # NAME -@@ -72,6 +73,10 @@ prior knowledge that the server supports HTTP/2 straight away. HTTPS requests - still do HTTP/2 the standard way with negotiated protocol version in the TLS - handshake. (Added in 7.49.0) - -+Since 8.10.0 if this option is set for an HTTPS request then the application -+layer protocol version (ALPN) offered to the server is only HTTP/2. Prior to -+that both HTTP/1.1 and HTTP/2 were offered. -+ - ## CURL_HTTP_VERSION_3 - - (Added in 7.66.0) This option makes libcurl attempt to use HTTP/3 to the host -@@ -89,6 +94,8 @@ Since curl 7.62.0: CURL_HTTP_VERSION_2TLS - - Before that: CURL_HTTP_VERSION_1_1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -108,9 +115,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md b/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md -index a39573e6a..4b8228b40 100644 ---- a/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md -+++ b/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md -@@ -10,6 +10,7 @@ Protocol: - See-also: - - CURLOPT_HTTP_VERSION (3) - - CURLOPT_MAXFILESIZE_LARGE (3) -+Added-in: 7.14.1 - --- - - # NAME -@@ -45,6 +46,8 @@ Only use this option if strictly necessary. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,10 +65,16 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Support for FTP added in 7.46.0. -+ -+# NOTES -+ -+This option is not working for HTTP when libcurl is built to use the hyper -+backend. - --Added in 7.14.1. Support for FTP added in 7.46.0. This option is not working --for HTTP when libcurl is built to use the hyper backend. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_INFILESIZE.md b/docs/libcurl/opts/CURLOPT_INFILESIZE.md -index 522bdb41a..8c9ab6243 100644 ---- a/docs/libcurl/opts/CURLOPT_INFILESIZE.md -+++ b/docs/libcurl/opts/CURLOPT_INFILESIZE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -50,6 +51,8 @@ and sending a different amount may lead to errors. - - Unset - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -74,10 +77,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - SMTP support added in 7.23.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md -index 712cd5802..2fb736484 100644 ---- a/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - All -+Added-in: 7.11.0 - --- - - # NAME -@@ -47,6 +48,8 @@ and sending a different amount may lead to errors. - - Unset - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -70,10 +73,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - SMTP support added in 7.23.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_INTERFACE.md b/docs/libcurl/opts/CURLOPT_INTERFACE.md -index f79a43078..ce5636ab6 100644 ---- a/docs/libcurl/opts/CURLOPT_INTERFACE.md -+++ b/docs/libcurl/opts/CURLOPT_INTERFACE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SOCKOPTFUNCTION (3) - - CURLOPT_TCP_NODELAY (3) - - CURLOPT_LOCALPORT (3) -+Added-in: 7.3 - --- - - # NAME -@@ -28,31 +29,37 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERFACE, char *interface); - - Pass a char pointer as parameter. This sets the *interface* name to use as - outgoing network interface. The name can be an interface name, an IP address, --or a hostname. -+or a hostname. If you prefer one of these, you can use the following special -+prefixes: - --If the parameter starts with "if!" then it is treated only as an interface --name. If the parameter starts with "host!" it is treated as either an IP --address or a hostname. -+* `if!\` - Interface name -+* `host!\` - IP address or hostname -+* `ifhost!\!\` - Interface name and IP address or hostname - --If "if!" is specified but the parameter does not match an existing interface, --*CURLE_INTERFACE_FAILED* is returned from the libcurl function used to perform --the transfer. -+If `if!` or `ifhost!` is specified but the parameter does not match an existing -+interface, *CURLE_INTERFACE_FAILED* is returned from the libcurl function used -+to perform the transfer. - - libcurl does not support using network interface names for this option on - Windows. - - We strongly advise against specifying the interface with a hostname, as it --causes libcurl to do a blocking name resolve call to retrieve the IP --address. That name resolve operation does **not** use DNS-over-HTTPS even if -+causes libcurl to do a blocking name resolve call to retrieve the IP address. -+That name resolve operation does **not** use DNS-over-HTTPS even if - CURLOPT_DOH_URL(3) is set. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL, use whatever the TCP stack finds suitable - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -72,9 +79,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+The `if!` and `host!` syntax was added in 7.24.0. -+ -+The `ifhost!` syntax was added in 8.9.0. - --The "if!" and "host!" syntax was added in 7.24.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md b/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md -index 508c76f13..15f1c8332 100644 ---- a/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md -+++ b/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_INTERLEAVEFUNCTION (3) - - CURLOPT_RTSP_REQUEST (3) -+Added-in: 7.20.0 - --- - - # NAME -@@ -34,6 +35,8 @@ anywhere. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md b/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md -index 7d2e52857..6f9754229 100644 ---- a/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RTSP_REQUEST (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -65,6 +66,8 @@ You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0) - NULL, the interleave data is then passed to the regular write function: - CURLOPT_WRITEFUNCTION(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -91,9 +94,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_IOCTLDATA.md b/docs/libcurl/opts/CURLOPT_IOCTLDATA.md -index ef33d7ce5..b9cd9a509 100644 ---- a/docs/libcurl/opts/CURLOPT_IOCTLDATA.md -+++ b/docs/libcurl/opts/CURLOPT_IOCTLDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_SEEKFUNCTION (3) - Protocol: - - All -+Added-in: 7.12.3 - --- - - # NAME -@@ -30,7 +31,9 @@ argument in the ioctl callback set with CURLOPT_IOCTLFUNCTION(3). - - # DEFAULT - --By default, the value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -61,9 +64,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.18.0. - --Added in 7.12.3. Deprecated since 7.18.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md -index 75e04c302..8aa01a9ef 100644 ---- a/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md -@@ -9,6 +9,7 @@ Protocol: - See-also: - - CURLOPT_IOCTLDATA (3) - - CURLOPT_SEEKFUNCTION (3) -+Added-in: 7.12.3 - --- - - # NAME -@@ -56,12 +57,14 @@ The *clientp* argument to the callback is set with the - CURLOPT_IOCTLDATA(3) option. - - **This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3) --instead to provide seeking! If CURLOPT_SEEKFUNCTION(3) is set, this -+instead to provide seeking. If CURLOPT_SEEKFUNCTION(3) is set, this - parameter is ignored when seeking. - - # DEFAULT - --By default, this parameter is set to NULL. Not used. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -92,9 +95,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.18.0. - --Added in 7.12.3. Deprecated since 7.18.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_IPRESOLVE.md b/docs/libcurl/opts/CURLOPT_IPRESOLVE.md -index acf0b3830..1b4369d22 100644 ---- a/docs/libcurl/opts/CURLOPT_IPRESOLVE.md -+++ b/docs/libcurl/opts/CURLOPT_IPRESOLVE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SSLVERSION (3) - Protocol: - - All -+Added-in: 7.10.8 - --- - - # NAME -@@ -52,6 +53,8 @@ Uses only IPv6 addresses. - - CURL_IPRESOLVE_WHATEVER - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -72,9 +75,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md -index f9000559e..e11f41a86 100644 ---- a/docs/libcurl/opts/CURLOPT_ISSUERCERT.md -+++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.19.0 - --- - - # NAME -@@ -45,6 +46,9 @@ which is returned if the setup of the SSL/TLS session has failed due to a - mismatch with the issuer of peer certificate (CURLOPT_SSL_VERIFYPEER(3) - has to be set too for the check to fail). (Added in 7.19.0) - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - The application does not have to keep the string around after setting this - option. - -@@ -52,6 +56,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md -index 142225da6..77f0d87bf 100644 ---- a/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.71.0 - --- - - # NAME -@@ -58,6 +59,8 @@ expects a filename as input. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -82,9 +85,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md b/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md -index 6a48523e8..fb52799f4 100644 ---- a/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md -+++ b/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_HTTPHEADER (3) - Protocol: - - HTTP -+Added-in: 7.51.0 - --- - - # NAME -@@ -41,6 +42,8 @@ Most applications do not need this option. - - 0, stop sending on error - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP. Added in 7.51.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_KEYPASSWD.md b/docs/libcurl/opts/CURLOPT_KEYPASSWD.md -index 408ccfbfb..08a08f7a0 100644 ---- a/docs/libcurl/opts/CURLOPT_KEYPASSWD.md -+++ b/docs/libcurl/opts/CURLOPT_KEYPASSWD.md -@@ -14,6 +14,7 @@ TLS-backend: - - mbedTLS - - Schannel - - wolfSSL -+Added-in: 7.17.0 - --- - - # NAME -@@ -32,16 +33,21 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KEYPASSWD, char *pwd); - - Pass a pointer to a null-terminated string as parameter. It is used as the - password required to use the CURLOPT_SSLKEY(3) or --CURLOPT_SSH_PRIVATE_KEYFILE(3) private key. You never need a pass phrase to -+CURLOPT_SSH_PRIVATE_KEYFILE(3) private key. You never need a passphrase to - load a certificate but you need one to load your private key. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,11 +66,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - This option was known as CURLOPT_SSLKEYPASSWD up to 7.16.4 and - CURLOPT_SSLCERTPASSWD up to 7.9.2. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md -index dfadcf436..5a674d3c4 100644 ---- a/docs/libcurl/opts/CURLOPT_KRBLEVEL.md -+++ b/docs/libcurl/opts/CURLOPT_KRBLEVEL.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_USE_SSL (3) - Protocol: - - FTP -+Added-in: 7.16.4 - --- - - # NAME -@@ -34,10 +35,15 @@ string to NULL to disable kerberos support for FTP. - The application does not have to keep the string around after setting this - option. - -+The application does not have to keep the string around after setting this -+option. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,10 +60,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - This option was known as CURLOPT_KRB4LEVEL up to 7.16.3 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_LOCALPORT.md b/docs/libcurl/opts/CURLOPT_LOCALPORT.md -index 94b5d50f8..a7cc9fdc7 100644 ---- a/docs/libcurl/opts/CURLOPT_LOCALPORT.md -+++ b/docs/libcurl/opts/CURLOPT_LOCALPORT.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_LOCALPORTRANGE (3) - Protocol: - - All -+Added-in: 7.15.2 - --- - - # NAME -@@ -35,6 +36,8 @@ this option is set. Valid port numbers are 1 - 65535. - - 0, disabled - use whatever the system thinks is fine - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md b/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md -index 4549cafe3..5d8c8a267 100644 ---- a/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md -+++ b/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_LOCALPORT (3) - Protocol: - - All -+Added-in: 7.15.2 - --- - - # NAME -@@ -38,6 +39,8 @@ setup failures. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.2 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md -index 5c879603a..969a2c418 100644 ---- a/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md -@@ -12,6 +12,7 @@ Protocol: - - LDAP - - POP3 - - SMTP -+Added-in: 7.34.0 - --- - - # NAME -@@ -47,10 +48,15 @@ disables the plain LOGIN (e.g. to prevent password snooping). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +73,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Support for OpenLDAP added in 7.82.0. - --Added in 7.34.0. Support for OpenLDAP added in 7.82.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md b/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md -index d0131a4ee..068c6572c 100644 ---- a/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md -+++ b/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -37,6 +38,8 @@ slow and abort. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,7 +54,7 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L); - res = curl_easy_perform(curl); - if(CURLE_OPERATION_TIMEDOUT == res) { -- printf("Timeout!\n"); -+ printf("Timeout.\n"); - } - /* always cleanup */ - curl_easy_cleanup(curl); -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md b/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md -index 06e38c194..819e7c1cc 100644 ---- a/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md -+++ b/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -34,6 +35,8 @@ library to consider it too slow and abort. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -48,7 +51,7 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 30L); - res = curl_easy_perform(curl); - if(CURLE_OPERATION_TIMEDOUT == res) { -- printf("Timeout!\n"); -+ printf("Timeout.\n"); - } - /* always cleanup */ - curl_easy_cleanup(curl); -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md b/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md -index afe62b91c..fd5c5f409 100644 ---- a/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md -+++ b/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAIL_RCPT (3) - Protocol: - - SMTP -+Added-in: 7.25.0 - --- - - # NAME -@@ -44,10 +45,15 @@ string is used then a pair of brackets are sent by libcurl as required by RFC - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.25.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAIL_FROM.md b/docs/libcurl/opts/CURLOPT_MAIL_FROM.md -index 52a8e51fc..16d045be2 100644 ---- a/docs/libcurl/opts/CURLOPT_MAIL_FROM.md -+++ b/docs/libcurl/opts/CURLOPT_MAIL_FROM.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAIL_RCPT (3) - Protocol: - - SMTP -+Added-in: 7.20.0 - --- - - # NAME -@@ -37,10 +38,15 @@ server which might cause the email to be rejected. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md b/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md -index 98b640e2e..3a6d17d0d 100644 ---- a/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md -+++ b/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAIL_FROM (3) - Protocol: - - SMTP -+Added-in: 7.20.0 - --- - - # NAME -@@ -31,6 +32,9 @@ SMTP mail request. The linked list should be a fully valid list of - **struct curl_slist** structs properly filled in. Use curl_slist_append(3) to - create the list and curl_slist_free_all(3) to clean up an entire list. - -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. -+ - When performing a mail transfer, each recipient should be specified within a - pair of angled brackets (\<\>), however, should you not use an angled bracket - as the first character libcurl assumes you provided a single email address and -@@ -44,10 +48,15 @@ When performing a mailing list expand (**EXPN** command), each recipient - should be specified using the mailing list name, such as `Friends` or - `London-Office`. - -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,9 +77,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0. The **VRFY** and **EXPN** logic was added in 7.34.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md b/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md -index d315d2bc8..f17d56151 100644 ---- a/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md -+++ b/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAIL_RCPT (3) - Protocol: - - SMTP -+Added-in: 8.2.0 - --- - - # NAME -@@ -44,6 +45,8 @@ RCPT TO command. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,11 +71,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - --This option was called CURLOPT_MAIL_RCPT_ALLLOWFAILS before 8.2.0 -+This option was called CURLOPT_MAIL_RCPT_ALLLOWFAILS (with three instead of -+two letter L) before 8.2.0 - --Added in 7.69.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md b/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md -index 6d92fa4af..c834d88c7 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md -+++ b/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.65.0 - --- - - # NAME -@@ -41,7 +42,9 @@ cache that is older than this set *age*, it is closed instead. - - # DEFAULT - --Default maximum age is set to 118 seconds. -+118 seconds -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.65.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md b/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md -index cd8b18dd0..3a368c825 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md -+++ b/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_MAXREDIRS (3) - Protocol: - - All -+Added-in: 7.7 - --- - - # NAME -@@ -27,18 +28,18 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXCONNECTS, long amount); - - # DESCRIPTION - --Pass a long. The set *amount* is the maximum number of simultaneously open --persistent connections that libcurl may cache in the pool associated with this --handle. The default is 5, and there is not much point in changing this value --unless you are perfectly aware of how this works. This concerns connections --using any of the protocols that support persistent connections. -+Pass a long. The set *amount* is the maximum number of connections that -+libcurl may keep alive in its connection cache after use. The default is 5, -+and there is not much point in changing this value unless you are perfectly -+aware of how this works. This concerns connections using any of the protocols -+that support persistent connections. - --When reaching the maximum limit, curl closes the oldest one in the cache to --prevent increasing the number of open connections. -+When reaching the maximum limit, curl closes the oldest connection present in -+the cache to prevent the number of connections from increasing. - - If you already have performed transfers with this curl handle, setting a --smaller CURLOPT_MAXCONNECTS(3) than before may cause open connections to --get closed unnecessarily. -+smaller CURLOPT_MAXCONNECTS(3) than before may cause open connections to get -+closed unnecessarily. - - If you add this easy handle to a multi handle, this setting is not - acknowledged, and you must instead use curl_multi_setopt(3) and the -@@ -48,6 +49,8 @@ CURLMOPT_MAXCONNECTS(3) option. - - 5 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md -index 36159709a..d28f3dc0e 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md -+++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAX_RECV_SPEED_LARGE (3) - Protocol: - - All -+Added-in: 7.10.8 - --- - - # NAME -@@ -28,6 +29,8 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXFILESIZE, long size); - Pass a long as parameter. This specifies the maximum accepted *size* (in - bytes) of a file to download. If the file requested is found larger than this - value, the transfer is aborted and *CURLE_FILESIZE_EXCEEDED* is returned. -+Passing a zero *size* disables this, and passing a negative *size* yields a -+*CURLE_BAD_FUNCTION_ARGUMENT*. - - The file size is not always known prior to the download start, and for such - transfers this option has no effect - even if the file transfer eventually -@@ -40,7 +43,9 @@ threshold. - - # DEFAULT - --None -+0, meaning disabled. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -51,17 +56,16 @@ int main(void) - if(curl) { - CURLcode ret; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- /* refuse to download if larger than 1000 bytes! */ -+ /* refuse to download if larger than 1000 bytes */ - curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, 1000L); - ret = curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - --Returns CURLE_OK -+Returns CURLE_OK if the size passed is valid or CURLE_BAD_FUNCTION_ARGUMENT if -+not. -diff --git a/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md -index d11a56225..ad6b10750 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md -@@ -11,6 +11,7 @@ Protocol: - - FTP - - HTTP - - MQTT -+Added-in: 7.11.0 - --- - - # NAME -@@ -31,7 +32,8 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXFILESIZE_LARGE, - Pass a curl_off_t as parameter. This specifies the maximum accepted *size* - (in bytes) of a file to download. If the file requested is found larger than - this value, the transfer is aborted and *CURLE_FILESIZE_EXCEEDED* is --returned. -+returned. Passing a zero *size* disables this, and passing a negative *size* -+yields a *CURLE_BAD_FUNCTION_ARGUMENT*. - - The file size is not always known prior to the download start, and for such - transfers this option has no effect - even if the file transfer eventually -@@ -42,7 +44,9 @@ threshold. - - # DEFAULT - --None -+0, meaning disabled. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -61,10 +65,9 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.11.0 -+# %AVAILABILITY% - - # RETURN VALUE - --Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -+Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -+CURLE_BAD_FUNCTION_ARGUMENT if the size passed is invalid. -diff --git a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md -index 79b87245b..5615f1fd1 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md -+++ b/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.80.0 - --- - - # NAME -@@ -43,7 +44,9 @@ If set to 0, this behavior is disabled: all connections are eligible for reuse. - - # DEFAULT - --Default *maxlifetime* is 0 seconds (i.e., disabled). -+0 seconds (i.e., disabled) -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.80.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAXREDIRS.md b/docs/libcurl/opts/CURLOPT_MAXREDIRS.md -index 751b22ed0..4f94f8d37 100644 ---- a/docs/libcurl/opts/CURLOPT_MAXREDIRS.md -+++ b/docs/libcurl/opts/CURLOPT_MAXREDIRS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_FOLLOWLOCATION (3) - Protocol: - - HTTP -+Added-in: 7.5 - --- - - # NAME -@@ -40,6 +41,8 @@ to get stuck in never-ending redirect loops. - - 30 (since 8.3.0), it was previously unlimited. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md b/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md -index 9e08a68dc..987693e84 100644 ---- a/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.15.5 - --- - - # NAME -@@ -43,6 +44,8 @@ This option does not affect transfer speeds done with FILE:// URLs. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md b/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md -index d8927269a..4619f272e 100644 ---- a/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_MAX_RECV_SPEED_LARGE (3) - Protocol: - - All -+Added-in: 7.15.5 - --- - - # NAME -@@ -44,6 +45,8 @@ This option does not affect transfer speeds done with FILE:// URLs. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,15 +58,13 @@ int main(void) - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); - /* cap the upload speed to 1000 bytes/sec */ - curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t)1000); -- /* (set some upload options as well!) */ -+ /* (set some upload options as well) */ - ret = curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.15.5 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MIMEPOST.md b/docs/libcurl/opts/CURLOPT_MIMEPOST.md -index 8a4edb10b..4cd3238bf 100644 ---- a/docs/libcurl/opts/CURLOPT_MIMEPOST.md -+++ b/docs/libcurl/opts/CURLOPT_MIMEPOST.md -@@ -13,6 +13,7 @@ Protocol: - - HTTP - - SMTP - - IMAP -+Added-in: 7.56.0 - --- - - # NAME -@@ -43,6 +44,8 @@ When setting CURLOPT_MIMEPOST(3) to NULL, libcurl resets the request - type for HTTP to the default to disable the POST. Typically that would mean it - is reset to GET. Instead you should set a desired request method explicitly. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,16 +68,14 @@ int main(void) - /* Set the form info */ - curl_easy_setopt(curl, CURLOPT_MIMEPOST, multipart); - -- curl_easy_perform(curl); /* post away! */ -+ curl_easy_perform(curl); /* post away */ - curl_mime_free(multipart); /* free the post data */ - } - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.56.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md b/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md -index f1f5fe0da..5175570e5 100644 ---- a/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md -@@ -11,6 +11,7 @@ Protocol: - - HTTP - - IMAP - - SMTP -+Added-in: 7.81.0 - --- - - # NAME -@@ -56,6 +57,8 @@ containing multipart form is sent, this is normally transmitted as - - 0, meaning disabled. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -88,9 +91,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Option added in 7.81.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NETRC.md b/docs/libcurl/opts/CURLOPT_NETRC.md -index 6b5e1d2e8..98568cc91 100644 ---- a/docs/libcurl/opts/CURLOPT_NETRC.md -+++ b/docs/libcurl/opts/CURLOPT_NETRC.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_USERPWD (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -30,8 +31,10 @@ This parameter controls the preference *level* of libcurl between using - usernames and passwords from your *~/.netrc* file, relative to usernames and - passwords in the URL supplied with CURLOPT_URL(3). - --On Windows, libcurl uses the file as *%HOME%/_netrc*. If *%HOME%* is --not set on Windows, libcurl falls back to *%USERPROFILE%*. -+On Windows, libcurl primarily checks for *.netrc* in *%HOME%*. If *%HOME%* is -+not set on Windows, libcurl falls back to *%USERPROFILE%*. If the file does -+not exist, it falls back to check if there is instead a file named *_netrc* - -+using an underscore instead of period. - - You can also tell libcurl a different filename to use with - CURLOPT_NETRC_FILE(3). -@@ -115,6 +118,8 @@ done with "macdef" that it finds. - - CURL_NETRC_IGNORED - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -130,9 +135,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NETRC_FILE.md b/docs/libcurl/opts/CURLOPT_NETRC_FILE.md -index 57b2acb78..4486b9c2d 100644 ---- a/docs/libcurl/opts/CURLOPT_NETRC_FILE.md -+++ b/docs/libcurl/opts/CURLOPT_NETRC_FILE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_USERNAME (3) - Protocol: - - All -+Added-in: 7.11.0 - --- - - # NAME -@@ -34,10 +35,15 @@ for a .netrc file in the current user's home directory. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.9 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md b/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md -index 51863440e..94c778c7e 100644 ---- a/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md -+++ b/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md -@@ -12,6 +12,7 @@ Protocol: - - SFTP - - SCP - - FILE -+Added-in: 7.16.4 - --- - - # NAME -@@ -38,6 +39,8 @@ this are *sftp://*, *scp://*, and *file://*. - - 0755 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +58,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md b/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md -index a04b99585..f3fba5589 100644 ---- a/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md -+++ b/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md -@@ -11,6 +11,7 @@ Protocol: - - SFTP - - SCP - - FILE -+Added-in: 7.16.4 - --- - - # NAME -@@ -36,6 +37,8 @@ The only protocols that can use this are *sftp://*, *scp://*, and *file://*. - - 0644 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NOBODY.md b/docs/libcurl/opts/CURLOPT_NOBODY.md -index 319b9ed61..e1643fb1b 100644 ---- a/docs/libcurl/opts/CURLOPT_NOBODY.md -+++ b/docs/libcurl/opts/CURLOPT_NOBODY.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -49,6 +50,8 @@ URL you request). - - 0, the body is transferred - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,7 +61,7 @@ int main(void) - if(curl) { - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); - -- /* get us the resource without a body - use HEAD! */ -+ /* get us the resource without a body - use HEAD */ - curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); - - /* Perform the request */ -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NOPROGRESS.md b/docs/libcurl/opts/CURLOPT_NOPROGRESS.md -index 6363b18c1..5f3d7322e 100644 ---- a/docs/libcurl/opts/CURLOPT_NOPROGRESS.md -+++ b/docs/libcurl/opts/CURLOPT_NOPROGRESS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_XFERINFOFUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -36,6 +37,8 @@ getting called. - - 1, meaning it normally runs without a progress meter. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NOPROXY.md b/docs/libcurl/opts/CURLOPT_NOPROXY.md -index 1f181c780..b27288733 100644 ---- a/docs/libcurl/opts/CURLOPT_NOPROXY.md -+++ b/docs/libcurl/opts/CURLOPT_NOPROXY.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PROXY (3) - - CURLOPT_PROXYAUTH (3) - - CURLOPT_PROXYTYPE (3) -+Added-in: 7.19.4 - --- - - # NAME -@@ -40,7 +41,7 @@ proxy for all hostnames, even if there is an environment variable set for it. - Enter IPv6 numerical addresses in the list of hostnames without enclosing - brackets: - -- "example.com,::1,localhost" -+ "example.com,::1,localhost" - - Since 7.86.0, IP addresses specified to this option can be provided using CIDR - notation: an appended slash and number specifies the number of "network bits" -@@ -50,6 +51,9 @@ would match all addresses starting with "192.168". - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # Environment variables - - If there is an environment variable called **no_proxy** (or **NO_PROXY**), -@@ -60,6 +64,8 @@ the same way. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_NOSIGNAL.md b/docs/libcurl/opts/CURLOPT_NOSIGNAL.md -index 7d147d0f9..4c9c5774a 100644 ---- a/docs/libcurl/opts/CURLOPT_NOSIGNAL.md -+++ b/docs/libcurl/opts/CURLOPT_NOSIGNAL.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME -@@ -26,7 +27,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NOSIGNAL, long onoff); - - If *onoff* is 1, libcurl uses no functions that install signal handlers or - any functions that cause signals to be sent to the process. This option is --here to allow multi-threaded unix applications to still set/use all timeout -+here to allow multi-threaded Unix applications to still set/use all timeout - options etc, without risking getting signals. - - If this option is set and libcurl has been built with the standard name -@@ -40,14 +41,14 @@ ignore SIGPIPE signals, which otherwise are sent by the system when trying to - send data to a socket which is closed in the other end. libcurl makes an - effort to never cause such SIGPIPE signals to trigger, but some operating - systems have no way to avoid them and even on those that have there are some --corner cases when they may still happen, contrary to our desire. In addition, --using *CURLAUTH_NTLM_WB* authentication could cause a SIGCHLD signal to be --raised. -+corner cases when they may still happen, contrary to our desire. - - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md -index 5118ffe96..1a73f2f14 100644 ---- a/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md -+++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SOCKOPTFUNCTION (3) - Protocol: - - All -+Added-in: 7.17.1 - --- - - # NAME -@@ -32,7 +33,9 @@ CURLOPT_OPENSOCKETFUNCTION(3). - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -81,9 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.17.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md -index 554ac8822..47bb7e132 100644 ---- a/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SOCKOPTFUNCTION (3) - Protocol: - - All -+Added-in: 7.17.1 - --- - - # NAME -@@ -70,11 +71,13 @@ CURLOPT_SOCKOPTFUNCTION(3) to signal that it already is connected. - - # DEFAULT - --The default behavior is the equivalent of this: -+The equivalent of this: - ~~~c - return socket(addr->family, addr->socktype, addr->protocol); - ~~~ - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -121,9 +124,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.17.1. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PASSWORD.md b/docs/libcurl/opts/CURLOPT_PASSWORD.md -index 3aa4489b6..68297111e 100644 ---- a/docs/libcurl/opts/CURLOPT_PASSWORD.md -+++ b/docs/libcurl/opts/CURLOPT_PASSWORD.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_USERPWD (3) - Protocol: - - All -+Added-in: 7.19.1 - --- - - # NAME -@@ -36,10 +37,15 @@ CURLOPT_USERNAME(3) option. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md -index 0c04b862b..ef7800432 100644 ---- a/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md -+++ b/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md -@@ -11,11 +11,12 @@ See-also: - - curl_url_set (3) - Protocol: - - All -+Added-in: 7.42.0 - --- - - # NAME - --CURLOPT_PATH_AS_IS - do not handle dot dot sequences -+CURLOPT_PATH_AS_IS - do not handle dot-dot sequences - - # SYNOPSIS - -@@ -34,7 +35,7 @@ This instructs libcurl to NOT squash sequences of "/../" or "/./" that may - exist in the URL's path part and that is supposed to be removed according to - RFC 3986 section 5.2.4. - --Some server implementations are known to (erroneously) require the dot dot -+Some server implementations are known to (erroneously) require the dot-dot - sequences to remain in the path and some clients want to pass these on in - order to try out server implementations. - -@@ -47,6 +48,8 @@ The corresponding flag for the curl_url_set(3) function is called - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.42.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md -index 357f387ef..10c7100cb 100644 ---- a/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md -+++ b/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md -@@ -18,6 +18,7 @@ TLS-backend: - - mbedTLS - - Secure Transport - - Schannel -+Added-in: 7.39.0 - --- - - # NAME -@@ -57,6 +58,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -116,7 +119,7 @@ footer: - -----END PUBLIC KEY----- - ~~~ - --# AVAILABILITY -+# HISTORY - - ## PEM/DER support - -@@ -142,6 +145,8 @@ footer: - - Other SSL backends not supported. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_PIPEWAIT.md b/docs/libcurl/opts/CURLOPT_PIPEWAIT.md -index 6fdbcee84..8226791d4 100644 ---- a/docs/libcurl/opts/CURLOPT_PIPEWAIT.md -+++ b/docs/libcurl/opts/CURLOPT_PIPEWAIT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_FRESH_CONNECT (3) - Protocol: - - HTTP -+Added-in: 7.43.0 - --- - - # NAME -@@ -52,6 +53,8 @@ and support level. - - 0 (off) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.43.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PORT.md b/docs/libcurl/opts/CURLOPT_PORT.md -index 15d57f503..812311bfd 100644 ---- a/docs/libcurl/opts/CURLOPT_PORT.md -+++ b/docs/libcurl/opts/CURLOPT_PORT.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -42,8 +43,10 @@ and therefore using a port number lower than zero or over 65535 causes a - - # DEFAULT - --By default this is 0 which makes it not used. This also makes port number zero --impossible to set with this API. -+0 which makes it not used. This also makes port number zero impossible to set -+with this API. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POST.md b/docs/libcurl/opts/CURLOPT_POST.md -index b2aef4f30..fe4656f17 100644 ---- a/docs/libcurl/opts/CURLOPT_POST.md -+++ b/docs/libcurl/opts/CURLOPT_POST.md -@@ -9,7 +9,8 @@ Protocol: - See-also: - - CURLOPT_HTTPPOST (3) - - CURLOPT_POSTFIELDS (3) -- - CURLOPT_PUT (3) -+ - CURLOPT_UPLOAD (3) -+Added-in: 7.1 - --- - - # NAME -@@ -71,6 +72,8 @@ you should set a new request type explicitly as described above. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -91,9 +94,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDS.md b/docs/libcurl/opts/CURLOPT_POSTFIELDS.md -index 11f64d7f7..8f6738f7c 100644 ---- a/docs/libcurl/opts/CURLOPT_POSTFIELDS.md -+++ b/docs/libcurl/opts/CURLOPT_POSTFIELDS.md -@@ -13,6 +13,7 @@ See-also: - Protocol: - - HTTP - - MQTT -+Added-in: 7.1 - --- - - # NAME -@@ -40,10 +41,9 @@ preserved by the calling application until the associated transfer finishes. - This behavior can be changed (so libcurl does copy the data) by instead using - the CURLOPT_COPYPOSTFIELDS(3) option. - --This POST is a normal **application/x-www-form-urlencoded** kind (and --libcurl sets that Content-Type by default when this option is used), which is --commonly used by HTML forms. Change Content-Type with --CURLOPT_HTTPHEADER(3). -+This POST is a normal **application/x-www-form-urlencoded** kind (and libcurl -+sets that Content-Type by default when this option is used), which is commonly -+used by HTML forms. Change Content-Type with CURLOPT_HTTPHEADER(3). - - You can use curl_easy_escape(3) to URL encode your data, if - necessary. It returns a pointer to an encoded string that can be passed as -@@ -57,9 +57,9 @@ CURLOPT_POSTFIELDS(3) to an empty string, or set CURLOPT_POST(3) to 1 and - CURLOPT_POSTFIELDSIZE(3) to 0. - - libcurl assumes this option points to a null-terminated string unless you also --set CURLOPT_POSTFIELDSIZE(3) to specify the length of the provided data, --which then is strictly required if you want to send off null bytes included in --the data. -+set CURLOPT_POSTFIELDSIZE(3) to specify the length of the provided data, which -+then is strictly required if you want to send off null bytes included in the -+data. - - Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header, - and libcurl adds that header automatically if the POST is either known to be -@@ -69,10 +69,15 @@ header with CURLOPT_HTTPHEADER(3) as usual. - To make **multipart/formdata** posts, check out the - CURLOPT_MIMEPOST(3) option combined with curl_mime_init(3). - -+Using this option multiple times makes the last set pointer override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -115,9 +120,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md -index 6fa83fdef..b23a486a3 100644 ---- a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md -+++ b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_POSTFIELDSIZE_LARGE (3) - Protocol: - - HTTP -+Added-in: 7.2 - --- - - # NAME -@@ -37,6 +38,8 @@ If you post more than 2GB, use CURLOPT_POSTFIELDSIZE_LARGE(3). - - -1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md -index a7adceca5..d06bf1a7e 100644 ---- a/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_POSTFIELDSIZE (3) - Protocol: - - HTTP -+Added-in: 7.11.1 - --- - - # NAME -@@ -37,6 +38,8 @@ CURLOPT_READFUNCTION(3) (if used) to signal the end of data. - - -1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POSTQUOTE.md b/docs/libcurl/opts/CURLOPT_POSTQUOTE.md -index fbd55fc50..7efca6044 100644 ---- a/docs/libcurl/opts/CURLOPT_POSTQUOTE.md -+++ b/docs/libcurl/opts/CURLOPT_POSTQUOTE.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - FTP - - SFTP -+Added-in: 7.1 - --- - - # NAME -@@ -32,12 +33,18 @@ after your FTP transfer request. The commands are only issued if no error - occur. The linked list should be a fully valid list of struct curl_slist - structs properly filled in as described for CURLOPT_QUOTE(3). - --Disable this operation again by setting a NULL to this option. -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,12 +66,11 @@ int main(void) - - curl_easy_cleanup(curl); - } -+ curl_slist_free_all(cmdlist); - } - ~~~ - --# AVAILABILITY -- --If support for the protocols are built-in. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_POSTREDIR.md b/docs/libcurl/opts/CURLOPT_POSTREDIR.md -index 4f63fd1cd..c56ba990a 100644 ---- a/docs/libcurl/opts/CURLOPT_POSTREDIR.md -+++ b/docs/libcurl/opts/CURLOPT_POSTREDIR.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_POSTFIELDS (3) - Protocol: - - HTTP -+Added-in: 7.19.1 - --- - - # NAME -@@ -48,6 +49,8 @@ when setting CURLOPT_FOLLOWLOCATION(3). - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,10 +72,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+This option was known as CURLOPT_POST301 up to 7.19.0 as it only supported the -+301 then. CURL_REDIR_POST_303 was added in 7.26.0. - --Added in 7.17.1. This option was known as CURLOPT_POST301 up to 7.19.0 as it --only supported the 301 then. CURL_REDIR_POST_303 was added in 7.26.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PREQUOTE.md b/docs/libcurl/opts/CURLOPT_PREQUOTE.md -index 887845875..12383ec4d 100644 ---- a/docs/libcurl/opts/CURLOPT_PREQUOTE.md -+++ b/docs/libcurl/opts/CURLOPT_PREQUOTE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_QUOTE (3) - Protocol: - - FTP -+Added-in: 7.9.5 - --- - - # NAME -@@ -29,8 +30,13 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREQUOTE, - Pass a pointer to a linked list of FTP commands to pass to the server after - the transfer type is set. The linked list should be a fully valid list of - struct curl_slist structs properly filled in as described for --CURLOPT_QUOTE(3). Disable this operation again by setting a NULL to this --option. -+CURLOPT_QUOTE(3). -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. - - These commands are not performed when a directory listing is performed, only - for file transfers. -@@ -42,6 +48,8 @@ this option does not. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,12 +70,11 @@ int main(void) - - curl_easy_cleanup(curl); - } -+ curl_slist_free_all(cmdlist); - } - ~~~ - --# AVAILABILITY -- --Along with the protocol support -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PREREQDATA.md b/docs/libcurl/opts/CURLOPT_PREREQDATA.md -index 821451bed..f94ecc6fc 100644 ---- a/docs/libcurl/opts/CURLOPT_PREREQDATA.md -+++ b/docs/libcurl/opts/CURLOPT_PREREQDATA.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PREREQFUNCTION (3) - Protocol: - - All -+Added-in: 7.80.0 - --- - - # NAME -@@ -33,6 +34,8 @@ argument in the pre-request callback set with CURLOPT_PREREQFUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.80.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md b/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md -index 0ddd412b9..8024a9a89 100644 ---- a/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PREREQDATA (3) - Protocol: - - All -+Added-in: 7.80.0 - --- - - # NAME -@@ -83,7 +84,9 @@ The pointer you set with CURLOPT_PREREQDATA(3). - - # DEFAULT - --By default, this is NULL and unused. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -114,9 +117,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.80.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PRE_PROXY.md b/docs/libcurl/opts/CURLOPT_PRE_PROXY.md -index 746a80833..666f90cd4 100644 ---- a/docs/libcurl/opts/CURLOPT_PRE_PROXY.md -+++ b/docs/libcurl/opts/CURLOPT_PRE_PROXY.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_PROXY (3) - Protocol: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -47,15 +48,20 @@ be used. Otherwise SOCKS4 is used as default. - Setting the pre proxy string to "" (an empty string) explicitly disables the - use of a pre proxy. - -+When you set a hostname to use, do not assume that there is any particular -+single port number used widely for proxies. Specify it. -+ - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --Default is NULL, meaning no pre proxy is used. -+NULL - --When you set a hostname to use, do not assume that there is any particular --single port number used widely for proxies. Specify it! -+# %PROTOCOLS% - - # EXAMPLE - -@@ -72,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PRIVATE.md b/docs/libcurl/opts/CURLOPT_PRIVATE.md -index 0af8fc2e8..580ba243d 100644 ---- a/docs/libcurl/opts/CURLOPT_PRIVATE.md -+++ b/docs/libcurl/opts/CURLOPT_PRIVATE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_VERBOSE (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -35,6 +36,8 @@ never does anything with this data. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md b/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md -index fc915750b..6f501f2ee 100644 ---- a/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md -+++ b/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_XFERINFOFUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -30,7 +31,9 @@ argument in the progress callback set with CURLOPT_PROGRESSFUNCTION(3). - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md b/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md -index 7bf26d637..eb0981e04 100644 ---- a/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_XFERINFOFUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -59,11 +60,13 @@ if you only download data, the upload size remains 0). Many times the callback - is called one or more times first, before it knows the data sizes so a program - must be made to handle that. - -+Return zero from the callback if everything is fine. -+ - If your callback function returns CURL_PROGRESSFUNC_CONTINUE it causes libcurl - to continue executing the default progress function. - --Returning any other non-zero value from this callback makes libcurl abort the --transfer and return *CURLE_ABORTED_BY_CALLBACK*. -+Return 1 from this callback to make libcurl abort the transfer and return -+*CURLE_ABORTED_BY_CALLBACK*. - - If you transfer data with the multi interface, this function is not called - during periods of idleness unless you call the appropriate libcurl function -@@ -74,8 +77,9 @@ get called. - - # DEFAULT - --By default, libcurl has an internal progress meter. That is rarely wanted by --users. -+NULL. libcurl has an internal progress meter. That is rarely wanted by users. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -114,10 +118,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED - - Deprecated since 7.32.0. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS.md b/docs/libcurl/opts/CURLOPT_PROTOCOLS.md -index a63821713..346d9f58f 100644 ---- a/docs/libcurl/opts/CURLOPT_PROTOCOLS.md -+++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - All -+Added-in: 7.19.4 - --- - - # NAME -@@ -28,7 +29,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROTOCOLS, long bitmask); - - This option is deprecated. We strongly recommend using - CURLOPT_PROTOCOLS_STR(3) instead because this option cannot control all --available protocols! -+available protocols. - - Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask - limits what protocols libcurl may use in the transfer. This allows you to have -@@ -73,6 +74,8 @@ CURLPROTO_TFTP - - All protocols built-in. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -93,9 +96,11 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.85.0. - --Added in 7.19.4. Deprecated since 7.85.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md -index f004d8d77..854520851 100644 ---- a/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md -+++ b/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md -@@ -12,6 +12,7 @@ See-also: - - curl_version_info (3) - Protocol: - - All -+Added-in: 7.85.0 - --- - - # NAME -@@ -48,14 +49,19 @@ You can set "ALL" as a short-cut to enable all protocols. Note that by setting - all, you may enable protocols that were not supported the day you write this - but are introduced in a future libcurl version. - --curl_version_info(3) can be used to get a list of all supported --protocols in the current libcurl. CURLINFO_SCHEME(3) is the recommended --way to figure out the protocol used in a previous transfer. -+curl_version_info(3) can be used to get a list of all supported protocols in -+the current libcurl. CURLINFO_SCHEME(3) is the recommended way to figure out -+the protocol used in a previous transfer. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to the internal default. - - # DEFAULT - - All protocols built-in - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,9 +81,7 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -- --Added in 7.85.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY.md b/docs/libcurl/opts/CURLOPT_PROXY.md -index a48f54e33..7c8455602 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_PROXYTYPE (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -40,6 +41,12 @@ defaults to using port 1080 for proxies. - The proxy string may be prefixed with [scheme]:// to specify which kind of - proxy is used. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+The application does not have to keep the string around after setting this -+option. -+ - ## http:// - - HTTP Proxy. Default when no scheme or proxy type is specified. -@@ -47,7 +54,7 @@ HTTP Proxy. Default when no scheme or proxy type is specified. - ## https:// - - HTTPS Proxy. (Added in 7.52.0 for OpenSSL and GnuTLS Since 7.87.0, it --also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport and -+also works for BearSSL, mbedTLS, Rustls, Schannel, Secure Transport and - wolfSSL.) - - This uses HTTP/1 by default. Setting CURLOPT_PROXYTYPE(3) to -@@ -69,15 +76,16 @@ SOCKS5 Proxy. - - SOCKS5 Proxy. Proxy resolves URL hostname. - --Without a scheme prefix, CURLOPT_PROXYTYPE(3) can be used to specify --which kind of proxy the string identifies. -+## -+ -+Without a scheme prefix, CURLOPT_PROXYTYPE(3) can be used to specify which -+kind of proxy the string identifies. - - When you tell the library to use an HTTP proxy, libcurl transparently converts - operations to HTTP even if you specify an FTP URL etc. This may have an impact --on what other features of the library you can use, such as --CURLOPT_QUOTE(3) and similar FTP specifics that do not work unless you --tunnel through the HTTP proxy. Such tunneling is activated with --CURLOPT_HTTPPROXYTUNNEL(3). -+on what other features of the library you can use, such as CURLOPT_QUOTE(3) -+and similar FTP specifics that do not work unless you tunnel through the HTTP -+proxy. Such tunneling is activated with CURLOPT_HTTPPROXYTUNNEL(3). - - Setting the proxy string to "" (an empty string) explicitly disables the use - of a proxy, even if there is an environment variable set for it. -@@ -88,12 +96,16 @@ user + password. - Unix domain sockets are supported for socks proxies since 7.84.0. Set - localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock - --The application does not have to keep the string around after setting this --option. -+When you set a hostname to use, do not assume that there is any particular -+single port number used widely for proxies. Specify it. - - When a proxy is used, the active FTP mode as set with *CUROPT_FTPPORT(3)*, - cannot be used. - -+Doing FTP over an HTTP proxy without CURLOPT_HTTPPROXYTUNNEL(3) set makes -+libcurl do HTTP with an FTP URL over the proxy. For such transfers, common FTP -+specific options do not work, for example CURLOPT_USE_SSL(3). -+ - # Environment variables - - libcurl respects the proxy environment variables named **http_proxy**, -@@ -109,10 +121,9 @@ variables. - - # DEFAULT - --Default is NULL, meaning no proxy is used. -+NULL - --When you set a hostname to use, do not assume that there is any particular --single port number used widely for proxies. Specify it! -+# %PROTOCOLS% - - # EXAMPLE - -@@ -128,7 +139,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Since 7.14.1 the proxy environment variable names can include the protocol - scheme. -@@ -138,6 +149,8 @@ Since 7.21.7 the proxy string supports the socks protocols as "schemes". - Since 7.50.2, unsupported schemes in proxy strings cause libcurl to return - error. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_PROXYAUTH.md b/docs/libcurl/opts/CURLOPT_PROXYAUTH.md -index ca5204e5e..1609cbafa 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYAUTH.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYAUTH.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_PROXYUSERPWD (3) - Protocol: - - All -+Added-in: 7.10.7 - --- - - # NAME -@@ -43,6 +44,8 @@ CURLOPT_HTTPAUTH(3) man page. - - CURLAUTH_BASIC - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.7 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYHEADER.md b/docs/libcurl/opts/CURLOPT_PROXYHEADER.md -index 8fbb964c3..e74210abc 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYHEADER.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYHEADER.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_HTTPHEADER (3) - Protocol: - - All -+Added-in: 7.37.0 - --- - - # NAME -@@ -38,12 +39,18 @@ NOT a header and cannot be replaced using this option. Only the lines - following the request-line are headers. Adding this method line in this list - of headers causes your request to send an invalid header. - --Pass a NULL to this to reset back to no custom headers. -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +76,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.37.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md b/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md -index f108bbf93..5086a4b38 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_PROXYUSERNAME (3) - Protocol: - - All -+Added-in: 7.19.1 - --- - - # NAME -@@ -27,19 +28,24 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPASSWORD, char *pwd); - - # DESCRIPTION - --Pass a char pointer as parameter, which should be pointing to the null-terminated --password to use for authentication with the proxy. -+Pass a char pointer as parameter, which should be pointing to the -+null-terminated password to use for authentication with the proxy. - --The CURLOPT_PROXYPASSWORD(3) option should be used in conjunction with --the CURLOPT_PROXYUSERNAME(3) option. -+The CURLOPT_PROXYPASSWORD(3) option should be used in conjunction with the -+CURLOPT_PROXYUSERNAME(3) option. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYPORT.md b/docs/libcurl/opts/CURLOPT_PROXYPORT.md -index 2a5b796af..b0113ac0e 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYPORT.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYPORT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_PROXYTYPE (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -30,15 +31,21 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPORT, long port); - We discourage use of this option. - - Pass a long with this option to set the proxy port to connect to unless it is --specified in the proxy string CURLOPT_PROXY(3) or uses 443 for https --proxies and 1080 for all others as default. -+specified in the proxy string CURLOPT_PROXY(3) or uses 443 for https proxies -+and 1080 for all others as default. -+ -+Disabling this option, setting it to zero, makes it not specified which makes -+libcurl use the default proxy port number or the port number specified in the -+proxy URL string. - - While this accepts a 'long', the port number is 16 bit so it cannot be larger - than 65535. - - # DEFAULT - --0, not specified which makes it use the default port -+0 -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -57,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYTYPE.md b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md -index 50af1d819..15aa2f845 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYTYPE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYTYPE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_PROXYPORT (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME -@@ -34,7 +35,7 @@ HTTP Proxy. Default. - ## CURLPROXY_HTTPS - - HTTPS Proxy using HTTP/1. (Added in 7.52.0 for OpenSSL and GnuTLS. Since --7.87.0, it also works for BearSSL, mbedTLS, rustls, Schannel, Secure Transport -+7.87.0, it also works for BearSSL, mbedTLS, Rustls, Schannel, Secure Transport - and wolfSSL.) - - ## CURLPROXY_HTTPS2 -@@ -63,6 +64,8 @@ SOCKS5 Proxy. - - SOCKS5 Proxy. Proxy resolves URL hostname. - -+## -+ - Often it is more convenient to specify the proxy type with the scheme part of - the CURLOPT_PROXY(3) string. - -@@ -70,6 +73,8 @@ the CURLOPT_PROXY(3) string. - - CURLPROXY_HTTP - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -88,9 +93,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md b/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md -index a2b7b2aec..7e0b0caba 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_USERNAME (3) - Protocol: - - All -+Added-in: 7.19.1 - --- - - # NAME -@@ -43,6 +44,8 @@ option. - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md b/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md -index 315761647..acfd86f7d 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md -+++ b/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_PROXYUSERNAME (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -38,9 +39,14 @@ Use CURLOPT_PROXYAUTH(3) to specify the authentication method. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --This is NULL by default. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -59,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md -index 82b136170..6365d5f22 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md -@@ -18,6 +18,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -55,12 +56,18 @@ method of verifying the peer's certificate chain. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again and switches back to -+internal default. -+ - The default value for this can be figured out with CURLINFO_CAINFO(3). - - # DEFAULT - - Built-in system specific - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -79,14 +86,14 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# NOTES - - For TLS backends that do not support certificate files, the - CURLOPT_PROXY_CAINFO(3) option is ignored. Refer to - https://curl.se/docs/ssl-compared.html - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md -index dff93aab4..91ef9a7c8 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md -@@ -21,6 +21,7 @@ TLS-backend: - - rustls - - Secure Transport - - Schannel -+Added-in: 7.77.0 - --- - - # NAME -@@ -57,6 +58,8 @@ This option overrides CURLOPT_PROXY_CAINFO(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -82,12 +85,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.77.0. -- --This option is supported by the rustls (since 7.82.0), OpenSSL, Secure --Transport and Schannel backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md -index 4a4f46d14..d0fce53ca 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md -@@ -16,6 +16,7 @@ TLS-backend: - - OpenSSL - - GnuTLS - - mbedTLS -+Added-in: 7.52.0 - --- - - # NAME -@@ -41,12 +42,18 @@ CURLOPT_PROXY_SSL_VERIFYPEER(3) is enabled (which it is by default). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again and switch back to -+internal default. -+ - The default value for this can be figured out with CURLINFO_CAPATH(3). - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,11 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -- --mbedTLS support added in 7.56.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md -index 498259756..9dfeeefeb 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md -@@ -15,6 +15,7 @@ TLS-backend: - - GnuTLS - - mbedTLS - - OpenSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -54,10 +55,15 @@ the CRL does not trigger this specific error. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md -index 33714c9e1..0b7e45dee 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md -@@ -15,6 +15,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.71.0 - --- - - # NAME -@@ -39,22 +40,26 @@ additional check is useful in multi-level PKI where one needs to enforce that - the peer certificate is from a specific branch of the tree. - - This option makes sense only when used in combination with the --CURLOPT_PROXY_SSL_VERIFYPEER(3) option. Otherwise, the result of the --check is not considered as failure. -+CURLOPT_PROXY_SSL_VERIFYPEER(3) option. Otherwise, the result of the check is -+not considered as failure. - - A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option, - which is returned if the setup of the SSL/TLS session has failed due to a --mismatch with the issuer of peer certificate --(CURLOPT_PROXY_SSL_VERIFYPEER(3) has to be set too for the check to --fail). -+mismatch with the issuer of peer certificate (CURLOPT_PROXY_SSL_VERIFYPEER(3) -+has to be set too for the check to fail). - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -73,9 +78,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL and GnuTLS backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md -index d8bcf09e6..002704fce 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md -@@ -14,6 +14,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.71.0 - --- - - # NAME -@@ -59,6 +60,8 @@ instead expects a filename as input. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -85,9 +88,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md -index cb1e4beca..6b417cb4a 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md -@@ -16,6 +16,7 @@ TLS-backend: - - mbedTLS - - Schannel - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -35,17 +36,22 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_KEYPASSWD, char *pwd); - This option is for connecting to an HTTPS proxy, not an HTTPS server. - - Pass a pointer to a null-terminated string as parameter. It is used as the --password required to use the CURLOPT_PROXY_SSLKEY(3) private key. You --never need a pass phrase to load a certificate but you need one to load your --private key. -+password required to use the CURLOPT_PROXY_SSLKEY(3) private key. You never -+need a passphrase to load a certificate but you need one to load your private -+key. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -63,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md b/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md -index a1a74258e..6bb75fc6a 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md -@@ -17,6 +17,7 @@ TLS-backend: - - GnuTLS - - mbedTLS - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -49,10 +50,15 @@ On mismatch, *CURLE_SSL_PINNEDPUBKEYNOTMATCH* is returned. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -109,7 +115,7 @@ footer: - -----END PUBLIC KEY----- - ~~~ - --# AVAILABILITY -+# HISTORY - - PEM/DER support: - -@@ -121,6 +127,8 @@ sha256 support: - - Other SSL backends not supported. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md b/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md -index d1b9dd95b..7083e252a 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SERVICE_NAME (3) - Protocol: - - All -+Added-in: 7.43.0 - --- - - # NAME -@@ -34,10 +35,15 @@ service. The default service name is **"HTTP"** for HTTP based proxies and - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - See above - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.43.0 for HTTP proxies, 7.49.0 for SOCKS5 proxies. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md -index 4b510b264..c26f00ca0 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md -@@ -17,6 +17,7 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -51,10 +52,15 @@ private key with CURLOPT_PROXY_SSLKEY(3). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -74,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md -index f14b73a19..fad7a6d70 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md -@@ -17,6 +17,7 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -38,16 +39,21 @@ the format of your client certificate used when connecting to an HTTPS proxy. - - Supported formats are "PEM" and "DER", except with Secure Transport or - Schannel. OpenSSL (versions 0.9.3 and later), Secure Transport (on iOS 5 or --later, or OS X 10.7 or later) and Schannel support "P12" for PKCS#12-encoded -+later, or macOS 10.7 or later) and Schannel support "P12" for PKCS#12-encoded - files. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - "PEM" - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,11 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md -index 05a41b9e7..2abbbb4df 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md -@@ -15,6 +15,7 @@ TLS-backend: - - OpenSSL - - Schannel - - Secure Transport -+Added-in: 7.71.0 - --- - - # NAME -@@ -49,6 +50,8 @@ expects a filename as input. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,9 +79,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md -index e954969ea..6352d0e86 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md -@@ -17,6 +17,7 @@ TLS-backend: - - mbedTLS - - Schannel - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -38,17 +39,22 @@ the filename of your private key used for connecting to the HTTPS proxy. The - default format is "PEM" and can be changed with - CURLOPT_PROXY_SSLKEYTYPE(3). - --(Windows, iOS and Mac OS X) This option is ignored by Secure Transport and -+(Windows, iOS and macOS) This option is ignored by Secure Transport and - Schannel SSL backends because they expect the private key to be already - present in the key chain or PKCS#12 file containing the certificate. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,11 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md -index 16ddd035f..672318d2b 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md -@@ -14,6 +14,7 @@ TLS-backend: - - OpenSSL - - BearSSL - - wolfSSL -+Added-in: 7.52.0 - --- - - # NAME -@@ -38,6 +39,11 @@ the format of your private key. Supported formats are "PEM", "DER" and "ENG". - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md -index 7f3554442..06ccac498 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.71.0 - --- - - # NAME -@@ -42,6 +43,8 @@ setting this. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,9 +79,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md -index 9fb935f24..1b1795210 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -59,10 +60,13 @@ TLSv1.2 - ## CURL_SSLVERSION_TLSv1_3 - - TLSv1.3 --The maximum TLS version can be set by using *one* of the --CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the --CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. --The MAX macros are not supported for WolfSSL. -+ -+## -+ -+The maximum TLS version can be set by using *one* of the CURL_SSLVERSION_MAX_ -+macros below. It is also possible to OR *one* of the CURL_SSLVERSION_ macros -+with *one* of the CURL_SSLVERSION_MAX_ macros. The MAX macros are not -+supported for wolfSSL. - - ## CURL_SSLVERSION_MAX_DEFAULT - -@@ -90,6 +94,8 @@ The flag defines maximum supported TLS version as TLSv1.2. - The flag defines maximum supported TLS version as TLSv1.3. - (Added in 7.54.0) - -+## -+ - In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were - documented to allow *only* the specified TLS version, but behavior was - inconsistent depending on the TLS library. -@@ -98,6 +104,8 @@ inconsistent depending on the TLS library. - - CURL_SSLVERSION_DEFAULT - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -116,9 +124,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md -index ce6a778b9..607760473 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md -@@ -18,7 +18,9 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -- - GnuTLS -+ - mbedTLS -+ - rustls -+Added-in: 7.52.0 - --- - - # NAME -@@ -37,24 +39,20 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_SSL_CIPHER_LIST, - # DESCRIPTION - - Pass a char pointer, pointing to a null-terminated string holding the list of --ciphers to use for the connection to the HTTPS proxy. The list must be --syntactically correct, it consists of one or more cipher strings separated by --colons. Commas or spaces are also acceptable separators but colons are --normally used, &!, &- and &+ can be used as operators. -+cipher suites to use for the TLS 1.2 (1.1, 1.0) connection to the HTTPS proxy. -+The list must be syntactically correct, it consists of one or more cipher suite -+strings separated by colons. - --For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**, --**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally --set when you compile OpenSSL. -+For setting TLS 1.3 ciphers see CURLOPT_PROXY_TLS13_CIPHERS(3). - --For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**, --**AES256-SHA:AES256-SHA256**, etc. -+A valid example of a cipher list is: -+~~~ -+"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" -+"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305" -+~~~ - --For BearSSL, valid examples of cipher lists include --**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using IANA names --**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**, --etc. --With BearSSL you do not add/remove ciphers. If one uses this option then all --known ciphers are disabled and only those passed in are enabled. -+For Schannel, you can use this option to set algorithms but not specific -+cipher suites. Refer to the ciphers lists document for algorithms. - - Find more details about cipher lists on this URL: - -@@ -63,9 +61,14 @@ Find more details about cipher lists on this URL: - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --NULL, use internal default -+NULL, use internal built-in list. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -77,20 +80,26 @@ int main(void) - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); - curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost"); -- curl_easy_setopt(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, "TLSv1"); -+ curl_easy_setopt(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, -+ "ECDHE-ECDSA-CHACHA20-POLY1305:" -+ "ECDHE-RSA-CHACHA20-POLY1305"); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+OpenSSL support added in 7.52.0. -+wolfSSL, Schannel, Secure Transport, and BearSSL support added in 7.87.0 -+mbedTLS support added in 8.8.0. -+Rustls support added in 8.10.0. - --Added in 7.52.0, in 7.83.0 for BearSSL -+Since curl 8.10.0 returns CURLE_NOT_BUILT_IN when not supported. - --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - --Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or --CURLE_OUT_OF_MEMORY if there was insufficient heap space. -+Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise. -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md -index 541b13cb8..02bc267c9 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -91,6 +92,8 @@ could be a privacy violation and unexpected. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -110,9 +113,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md -index 01cbdb913..0d195daf7 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -55,7 +56,7 @@ an error and leaving the flag untouched. - From 7.66.0: treats 1 and 2 the same. - - When the *verify* value is 0L, the connection succeeds regardless of the --names used in the certificate. Use that ability with caution! -+names used in the certificate. Use that ability with caution. - - See also CURLOPT_PROXY_SSL_VERIFYPEER(3) to verify the digital signature - of the proxy certificate. -@@ -64,6 +65,8 @@ of the proxy certificate. - - 2 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -81,11 +84,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0. -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md -index 86afeb72b..b29a4235f 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.52.0 - --- - - # NAME -@@ -66,6 +67,8 @@ the correct end-point. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -83,11 +86,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md -index 90b6166ef..ba5d97edb 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md -@@ -14,8 +14,11 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -- - rustls - - Schannel -+ - wolfSSL -+ - mbedTLS -+ - rustls -+Added-in: 7.61.0 - --- - - # NAME -@@ -38,20 +41,28 @@ cipher suites to use for the TLS 1.3 connection to a proxy. The list must be - syntactically correct, it consists of one or more cipher suite strings - separated by colons. - -+For setting TLS 1.2 (1.1, 1.0) ciphers see CURLOPT_PROXY_SSL_CIPHER_LIST(3). -+ -+A valid example of a cipher list is: -+~~~ -+"TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256" -+~~~ -+ - Find more details about cipher lists on this URL: - - https://curl.se/docs/ssl-ciphers.html - --This option is currently used only when curl is built to use OpenSSL 1.1.1 or --later. If you are using a different SSL backend you can try setting TLS 1.3 --cipher suites by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option. -- - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --NULL, use internal default -+NULL, use internal built-in list -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -70,10 +81,19 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+OpenSSL support added in 7.61.0, available when built with OpenSSL \>= 1.1.1. -+Schannel support added in 7.87.0. -+LibreSSL support added in 8.3.0, available when built with LibreSSL \>= 3.4.1. -+wolfSSL support added in 8.10.0. -+mbedTLS support added in 8.10.0, available when built with mbedTLS \>= 3.6.0. -+Rustls support added in 8.10.0. -+ -+Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites were set -+by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option. - --Added in 7.61.0. --Available when built with OpenSSL \>= 1.1.1. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md -index e45f69e9b..b92b2e27d 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md -@@ -14,6 +14,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.52.0 - --- - - # NAME -@@ -39,10 +40,15 @@ CURLOPT_PROXY_TLSAUTH_USERNAME(3) option also be set. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md -index a10d78c5e..436a57092 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md -@@ -14,6 +14,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.52.0 - --- - - # NAME -@@ -35,21 +36,26 @@ Pass a pointer to a null-terminated string as parameter. The string should be - the method of the TLS authentication used for the HTTPS connection. Supported - method is "SRP". - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to internal default. -+ -+The application does not have to keep the string around after setting this -+option. -+ - ## SRP - - TLS-SRP authentication. Secure Remote Password authentication for TLS is - defined in RFC 5054 and provides mutual authentication if both sides have a - shared secret. To use TLS-SRP, you must also set the --CURLOPT_PROXY_TLSAUTH_USERNAME(3) and --CURLOPT_PROXY_TLSAUTH_PASSWORD(3) options. -- --The application does not have to keep the string around after setting this --option. -+CURLOPT_PROXY_TLSAUTH_USERNAME(3) and CURLOPT_PROXY_TLSAUTH_PASSWORD(3) -+options. - - # DEFAULT - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,12 +75,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0 -- --You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this --to work. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md -index 8d7b221b8..6a25f74d7 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md -@@ -14,6 +14,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.52.0 - --- - - # NAME -@@ -39,10 +40,15 @@ CURLOPT_PROXY_TLSAUTH_PASSWORD(3) option also be set. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.52.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md b/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md -index 5daf5df37..a0ac94912 100644 ---- a/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md -+++ b/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TRANSFERTEXT (3) - Protocol: - - All -+Added-in: 7.18.0 - --- - - # NAME -@@ -38,6 +39,8 @@ doing FTP via a proxy. Beware that not all proxies support this feature. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_PUT.md b/docs/libcurl/opts/CURLOPT_PUT.md -index 6eb3a6bb1..43bf645de 100644 ---- a/docs/libcurl/opts/CURLOPT_PUT.md -+++ b/docs/libcurl/opts/CURLOPT_PUT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_UPLOAD (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -37,6 +38,8 @@ This option is **deprecated** since version 7.12.1. Use CURLOPT_UPLOAD(3). - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -78,9 +81,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.12.1. - --Deprecated since 7.12.1. Do not use. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md -index 3e0d64ced..e13b43ca0 100644 ---- a/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md -+++ b/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RESOLVE (3) - Protocol: - - All -+Added-in: 7.87.0 - --- - - # NAME -@@ -37,6 +38,8 @@ possible (though short-lived) leak of associated resources. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.87.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_QUOTE.md b/docs/libcurl/opts/CURLOPT_QUOTE.md -index 4bdc1913c..410347142 100644 ---- a/docs/libcurl/opts/CURLOPT_QUOTE.md -+++ b/docs/libcurl/opts/CURLOPT_QUOTE.md -@@ -12,6 +12,7 @@ See-also: - Protocol: - - FTP - - SFTP -+Added-in: 7.1 - --- - - # NAME -@@ -36,7 +37,9 @@ of 'struct curl_slist' structs properly filled in with text strings. Use - curl_slist_append(3) to append strings (commands) to the list, and clear - the entire list afterwards with curl_slist_free_all(3). - --Disable this operation again by setting a NULL to this option. -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. libcurl does not copy the list, -+it needs to be kept around until after the transfer has completed. - - When speaking to an FTP server, prefix the command with an asterisk (*) to - make libcurl continue even if the command fails as by default libcurl stops at -@@ -127,6 +130,8 @@ See ln. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -148,13 +153,17 @@ int main(void) - - curl_easy_cleanup(curl); - } -+ -+ curl_slist_free_all(cmdlist); - } - ~~~ - --# AVAILABILITY -+# HISTORY - - SFTP support added in 7.16.3. *-prefix for SFTP added in 7.24.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK -diff --git a/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md b/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md -index 6840fbc29..41cc75f20 100644 ---- a/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md -+++ b/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md -@@ -10,6 +10,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.7 - --- - - # NAME -@@ -28,39 +29,16 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_RANDOM_FILE, char *path); - - Deprecated option. It serves no purpose anymore. - --Pass a char pointer to a null-terminated filename. The file might be used to --read from to seed the random engine for SSL and more. -- --The application does not have to keep the string around after setting this --option. -- - # DEFAULT - - NULL, not used - --# EXAMPLE -- --~~~c --int main(void) --{ -- CURL *curl = curl_easy_init(); -- if(curl) { -- CURLcode res; -- curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- curl_easy_setopt(curl, CURLOPT_RANDOM_FILE, "junk.txt"); -- res = curl_easy_perform(curl); -- curl_easy_cleanup(curl); -- } --} --~~~ -- --# AVAILABILITY -+# DEPRECATED - --Only with OpenSSL versions before 1.1.0. -+Deprecated since 7.84.0. - --This option was deprecated in 7.84.0. -+# %AVAILABILITY% - - # RETURN VALUE - --Returns CURLE_OK on success or --CURLE_OUT_OF_MEMORY if there was insufficient heap space. -+Returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_RANGE.md b/docs/libcurl/opts/CURLOPT_RANGE.md -index 0a8343db3..6d728b164 100644 ---- a/docs/libcurl/opts/CURLOPT_RANGE.md -+++ b/docs/libcurl/opts/CURLOPT_RANGE.md -@@ -15,6 +15,7 @@ Protocol: - - FILE - - RTSP - - SFTP -+Added-in: 7.1 - --- - - # NAME -@@ -49,7 +50,8 @@ RTSP, byte ranges are **not** permitted. Instead, ranges should be given in - For HTTP PUT uploads this option should not be used, since it may conflict with - other options. - --Pass a NULL to this option to disable the use of ranges. -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. - - The application does not have to keep the string around after setting this - option. -@@ -58,6 +60,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,10 +80,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - FILE since 7.18.0, RTSP since 7.20.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK on success or -diff --git a/docs/libcurl/opts/CURLOPT_READDATA.md b/docs/libcurl/opts/CURLOPT_READDATA.md -index 20eb3c6d4..ae3ac3c48 100644 ---- a/docs/libcurl/opts/CURLOPT_READDATA.md -+++ b/docs/libcurl/opts/CURLOPT_READDATA.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - All -+Added-in: 7.9.7 - --- - - # NAME -@@ -40,7 +41,9 @@ might experience crashes. - - # DEFAULT - --By default, this is a FILE * to stdin. -+stdin -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -65,11 +68,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - This option was once known by the older name CURLOPT_INFILE, the name - CURLOPT_READDATA(3) was introduced in 7.9.7. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - This returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_READFUNCTION.md b/docs/libcurl/opts/CURLOPT_READFUNCTION.md -index 06d2e638a..9e3c3d1f8 100644 ---- a/docs/libcurl/opts/CURLOPT_READFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_READFUNCTION.md -@@ -13,6 +13,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -72,7 +73,9 @@ and it allows for better error checking. - - # DEFAULT - --The default internal read callback is fread(). -+fread(3) -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -83,7 +86,7 @@ size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userdata) - curl_off_t nread; - - /* copy as much data as possible into the 'ptr' buffer, but no more than -- 'size' * 'nmemb' bytes! */ -+ 'size' * 'nmemb' bytes. */ - size_t retcode = fread(ptr, size, nmemb, readhere); - - nread = (curl_off_t)retcode; -@@ -111,11 +114,13 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - CURL_READFUNC_PAUSE return code was added in 7.18.0 and CURL_READFUNC_ABORT - was added in 7.12.1. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - This returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md -index df6cb7163..28fd76b10 100644 ---- a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md -+++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_REDIR_PROTOCOLS_STR (3) - Protocol: - - HTTP -+Added-in: 7.19.4 - --- - - # NAME -@@ -29,7 +30,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS, long bitmask); - - This option is deprecated. We strongly recommend using - CURLOPT_REDIR_PROTOCOLS_STR(3) instead because this option cannot --control all available protocols! -+control all available protocols. - - Pass a long that holds a bitmask of CURLPROTO_* defines. If used, this bitmask - limits what protocols libcurl may use in a transfer that it follows to in a -@@ -83,6 +84,8 @@ HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). - Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 - SMB and SMBS. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -103,10 +106,11 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.85.0. - --Added in 7.19.4, before then it would follow all protocols. Deprecated --since 7.85.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md -index 69c2e7c9f..2f14b04d0 100644 ---- a/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md -+++ b/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_REDIR_PROTOCOLS (3) - Protocol: - - HTTP -+Added-in: 7.85.0 - --- - - # NAME -@@ -32,8 +33,8 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_REDIR_PROTOCOLS_STR, - Pass a pointer to a string that holds a comma-separated list of case - insensitive protocol names (URL schemes). That list limits what protocols - libcurl may use in a transfer that it follows to in a redirect when --CURLOPT_FOLLOWLOCATION(3) is enabled. This option allows applications to --limit specific transfers to only be allowed to use a subset of protocols in -+CURLOPT_FOLLOWLOCATION(3) is enabled. This option allows applications to limit -+specific transfers to only be allowed to use a subset of protocols in - redirections. - - Protocols denied by CURLOPT_PROTOCOLS_STR(3) are not overridden by this -@@ -55,6 +56,12 @@ but are introduced in a future libcurl version. - If trying to set a non-existing protocol or if no matching protocol at all is - set, it returns error. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to internal default. -+ -+The application does not have to keep the string around after setting this -+option. -+ - # DEFAULT - - HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). -@@ -62,6 +69,8 @@ HTTP, HTTPS, FTP and FTPS (Added in 7.65.2). - Older versions defaulted to all protocols except FILE, SCP and since 7.40.0 - SMB and SMBS. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -81,9 +90,7 @@ int main(int argc, char **argv) - } - ~~~ - --# AVAILABILITY -- --Added in 7.85.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_REFERER.md b/docs/libcurl/opts/CURLOPT_REFERER.md -index f5ac9a8b3..e666411cf 100644 ---- a/docs/libcurl/opts/CURLOPT_REFERER.md -+++ b/docs/libcurl/opts/CURLOPT_REFERER.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_USERAGENT (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -34,10 +35,15 @@ set any custom header with CURLOPT_HTTPHEADER(3). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built with HTTP support -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md b/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md -index 582b88fa1..fa4ff1d17 100644 ---- a/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md -+++ b/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - HTTP -+Added-in: 7.55.0 - --- - - # NAME -@@ -33,10 +34,18 @@ instead of the path as extracted from the URL. - libcurl passes on the verbatim string in its request without any filter or - other safe guards. That includes white space and control characters. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+The application does not have to keep the string around after setting this -+option. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RESOLVE.md b/docs/libcurl/opts/CURLOPT_RESOLVE.md -index 800e3a82d..a6db5b428 100644 ---- a/docs/libcurl/opts/CURLOPT_RESOLVE.md -+++ b/docs/libcurl/opts/CURLOPT_RESOLVE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_IPRESOLVE (3) - Protocol: - - All -+Added-in: 7.21.3 - --- - - # NAME -@@ -33,11 +34,12 @@ list of **struct curl_slist** structs properly filled in. Use - curl_slist_append(3) to create the list and curl_slist_free_all(3) to clean up - an entire list. - -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. -+ - Each resolve rule to add should be written using the format - --~~~c -- [+]HOST:PORT:ADDRESS[,ADDRESS] --~~~ -+ [+]HOST:PORT:ADDRESS[,ADDRESS] - - HOST is the name libcurl wants to resolve, PORT is the port number of the - service where libcurl wants to connect to the HOST and ADDRESS is one or more -@@ -45,13 +47,17 @@ numerical IP addresses. If you specify multiple IP addresses they need to be - separated by comma. If libcurl is built to support IPv6, each of the ADDRESS - entries can of course be either IPv4 or IPv6 style addressing. - -+Specify the host as a single ampersand (`*`) to match all names. This wildcard -+is resolved last so any resolve with a specific host and port number is given -+priority. -+ - This option effectively populates the DNS cache with entries for the host+port - pair so redirects and everything that operations against the HOST+PORT instead - use your provided ADDRESS. - --The optional leading "+" specifies that the new entry should time-out. Entries --added without the leading plus character never times out whereas entries added --with "+HOST:..." times out just like ordinary DNS cache entries. -+The optional leading plus (`+`) specifies that the new entry should timeout. -+Entries added without the leading plus character never times out whereas -+entries added with `+HOST:...` times out just like ordinary DNS cache entries. - - If the DNS cache already has an entry for the given host+port pair, the new - entry overrides the former one. -@@ -62,17 +68,20 @@ setting of CURLOPT_IPRESOLVE(3) to a different IP version. - To remove names from the DNS cache again, to stop providing these fake - resolves, include a string in the linked list that uses the format - --~~~c -- -HOST:PORT --~~~ -+ -HOST:PORT - - The entry to remove must be prefixed with a dash, and the hostname and port - number must exactly match what was added previously. - -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -97,7 +106,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Added in 7.21.3. Removal support added in 7.42.0. - -@@ -108,6 +117,8 @@ Support for providing multiple IP addresses per entry was added in 7.59.0. - Support for adding non-permanent entries by using the "+" prefix was added in - 7.75.0. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md b/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md -index f1fdc4e98..e6ec836a0 100644 ---- a/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md -+++ b/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RESOLVER_START_FUNCTION (3) - Protocol: - - All -+Added-in: 7.59.0 - --- - - # NAME -@@ -34,6 +35,8 @@ CURLOPT_RESOLVER_START_FUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.59.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md b/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md -index 3ff66168d..2be7bcde6 100644 ---- a/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RESOLVER_START_DATA (3) - Protocol: - - All -+Added-in: 7.59.0 - --- - - # NAME -@@ -52,6 +53,8 @@ resolve to fail. - - NULL (No callback) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -77,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.59.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RESUME_FROM.md b/docs/libcurl/opts/CURLOPT_RESUME_FROM.md -index 34f84e3b8..681c1ace2 100644 ---- a/docs/libcurl/opts/CURLOPT_RESUME_FROM.md -+++ b/docs/libcurl/opts/CURLOPT_RESUME_FROM.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_RESUME_FROM_LARGE (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -43,6 +44,8 @@ CURLOPT_RESUME_FROM_LARGE(3) instead. - - 0, not used - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md b/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md -index 7326a3df5..061890dd8 100644 ---- a/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_RESUME_FROM (3) - Protocol: - - All -+Added-in: 7.11.0 - --- - - # NAME -@@ -41,6 +42,8 @@ file to the remote target file. - - 0, not used - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -68,9 +71,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.11.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md b/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md -index a02cd85ab..7b00069e0 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_RTSP_SERVER_CSEQ (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -35,6 +36,8 @@ increments from this new number henceforth. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md b/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md -index 1a2603486..4173ce624 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RTSP_STREAM_URI (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -111,6 +112,8 @@ application a chance to run. - - # DEFAULT - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -120,7 +123,7 @@ int main(void) - if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/"); -- /* ask for options! */ -+ /* ask for options */ - curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); -@@ -128,9 +131,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md b/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md -index 096132bb3..01ea910a7 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_RTSP_STREAM_URI (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -34,6 +35,8 @@ unimplemented. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,9 +53,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md b/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md -index 39fd1621e..36dc1eace 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RTSP_STREAM_URI (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -35,10 +36,15 @@ server sets it in a response. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md b/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md -index ecd2eff2a..074b39486 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RTSP_TRANSPORT (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -39,10 +40,15 @@ to. (e.g. the CURLOPT_URL(3) for the above examples might be set to - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - "*" - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +66,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md b/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md -index da98ee900..6e28650ca 100644 ---- a/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md -+++ b/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_RTSP_SESSION_ID (3) - Protocol: - - RTSP -+Added-in: 7.20.0 - --- - - # NAME -@@ -38,6 +39,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.20.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md -index f7012f27e..f4058fc39 100644 ---- a/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md -+++ b/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_USERPWD (3) - Protocol: - - IMAP -+Added-in: 7.66.0 - --- - - # NAME -@@ -30,19 +31,27 @@ Pass a char pointer as parameter, which should be pointing to the - null-terminated authorization identity (*authzid*) for the transfer. Only - applicable to the PLAIN SASL authentication mechanism where it is optional. - --When not specified only the authentication identity (*authcid*) as --specified by the username is sent to the server, along with the password. The --server derives a *authzid* from the *authcid* when not provided, which --it then uses internally. -+When not specified only the authentication identity (*authcid*) as specified -+by the username is sent to the server, along with the password. The server -+derives a *authzid* from the *authcid* when not provided, which it then uses -+internally. - --When the *authzid* is specified, the use of which is server dependent, it --can be used to access another user's inbox, that the user has been granted --access to, or a shared mailbox for example. -+When the *authzid* is specified, the use of which is server dependent, it can -+be used to access another user's inbox, that the user has been granted access -+to, or a shared mailbox for example. -+ -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. - - # DEFAULT - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.66.0. Support for OpenLDAP added in 7.82.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SASL_IR.md b/docs/libcurl/opts/CURLOPT_SASL_IR.md -index ebc4c4aff..25d849500 100644 ---- a/docs/libcurl/opts/CURLOPT_SASL_IR.md -+++ b/docs/libcurl/opts/CURLOPT_SASL_IR.md -@@ -11,6 +11,7 @@ See-also: - Protocol: - - SMTP - - IMAP -+Added-in: 7.31.0 - --- - - # NAME -@@ -46,6 +47,8 @@ SASL-IR CAPABILITY. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -62,9 +65,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.31.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SEEKDATA.md b/docs/libcurl/opts/CURLOPT_SEEKDATA.md -index e660cb6a3..fd93aacd2 100644 ---- a/docs/libcurl/opts/CURLOPT_SEEKDATA.md -+++ b/docs/libcurl/opts/CURLOPT_SEEKDATA.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_STDERR (3) - Protocol: - - All -+Added-in: 7.18.0 - --- - - # NAME -@@ -34,6 +35,8 @@ CURLOPT_SEEKFUNCTION(3) option, this is the pointer you get as input. - - If you do not set this, NULL is passed to the callback. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,8 +64,6 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.0 -+# %AVAILABILITY% - - # RETURN VALUE -diff --git a/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md b/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md -index ac37cc596..ea8ff5e30 100644 ---- a/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_STDERR (3) - Protocol: - - All -+Added-in: 7.18.0 - --- - - # NAME -@@ -59,11 +60,13 @@ done by instead reading from the input or similar. - - If you forward the input arguments directly to fseek(3) or lseek(3), note that - the data type for *offset* is not the same as defined for curl_off_t on --many systems! -+many systems. - - # DEFAULT - --By default, this is NULL and unused. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -91,9 +94,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.18.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md -index 6c7d74fc8..03f8eddf3 100644 ---- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md -+++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md -@@ -15,6 +15,7 @@ Protocol: - - SMTP - - SFTP - - SCP -+Added-in: 7.20.0 - --- - - # NAME -@@ -46,6 +47,8 @@ This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT. - - None - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,12 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10.8. Used under this name since 7.20.0 -- --Support for SSH is predicated on a new enough (1.11.0) version of libssh2 --being available when compiling libcurl. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md -index 87e2820ca..57071d6d3 100644 ---- a/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md -@@ -15,6 +15,7 @@ Protocol: - - SMTP - - SFTP - - SCP -+Added-in: 8.6.0 - --- - - # NAME -@@ -48,6 +49,8 @@ This is the millisecond version of CURLOPT_SERVER_RESPONSE_TIMEOUT(3). - - None - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +69,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 8.6.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md -index 8276253b5..b928c9102 100644 ---- a/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md -+++ b/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md -@@ -15,6 +15,7 @@ Protocol: - - POP3 - - SMTP - - LDAP -+Added-in: 7.43.0 - --- - - # NAME -@@ -39,10 +40,15 @@ allows you to change them. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - See above - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,10 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.43.0 for HTTP, 7.49.0 for FTP, IMAP, POP3 and SMTP, --7.82.0 for OpenLDAP. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SHARE.md b/docs/libcurl/opts/CURLOPT_SHARE.md -index 308d57af3..4e64cc748 100644 ---- a/docs/libcurl/opts/CURLOPT_SHARE.md -+++ b/docs/libcurl/opts/CURLOPT_SHARE.md -@@ -9,6 +9,7 @@ See-also: - - CURLSHOPT_SHARE (3) - Protocol: - - All -+Added-in: 7.10 - --- - - # NAME -@@ -47,6 +48,8 @@ Set this option to NULL again to stop using that share object. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -77,9 +80,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md b/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md -index 678073745..dbf75da3b 100644 ---- a/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md -+++ b/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_SOCKOPTFUNCTION (3) - Protocol: - - All -+Added-in: 7.16.0 - --- - - # NAME -@@ -30,7 +31,9 @@ argument in the sockopt callback set with CURLOPT_SOCKOPTFUNCTION(3). - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md -index e35934be1..fbc3d8804 100644 ---- a/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_SOCKOPTDATA (3) - Protocol: - - All -+Added-in: 7.16.0 - --- - - # NAME -@@ -72,7 +73,9 @@ not attempt to connect (again). - - # DEFAULT - --By default, this callback is NULL and unused. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -120,10 +123,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.0. The *CURL_SOCKOPT_ALREADY_CONNECTED* return code was --added in 7.21.5. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md b/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md -index 937da2c02..9a965933f 100644 ---- a/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md -+++ b/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_PROXYTYPE (3) - Protocol: - - All -+Added-in: 7.55.0 - --- - - # NAME -@@ -36,6 +37,8 @@ password with the CURLOPT_PROXYUSERPWD(3) option. - - CURLAUTH_BASIC|CURLAUTH_GSSAPI - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.55.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md -index b46713017..5bb2e42e5 100644 ---- a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md -+++ b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md -@@ -6,9 +6,10 @@ Section: 3 - Source: libcurl - See-also: - - CURLOPT_PROXY (3) -- - CURLOPT_SOCKS5_GSSAPI_SERVICE (3) -+ - CURLOPT_PROXY_SERVICE_NAME (3) - Protocol: - - All -+Added-in: 7.19.4 - --- - - # NAME -@@ -35,6 +36,8 @@ negotiation. - - ? - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -52,9 +55,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md -index 86879589b..fe0c22df6 100644 ---- a/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md -+++ b/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_PROXYTYPE (3) - Protocol: - - All -+Added-in: 7.19.4 - --- - - # NAME -@@ -39,6 +40,8 @@ option. - - See above - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -56,9 +59,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.49.0 - --Added in 7.19.4, deprecated in 7.49.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md b/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md -index e83d0a088..f111efe64 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md -@@ -11,6 +11,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.16.1 - --- - - # NAME -@@ -40,6 +41,8 @@ authentication. - - CURLSSH_AUTH_ANY (all available) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --CURLSSH_AUTH_HOST was added in 7.16.1, CURLSSH_AUTH_AGENT was added in 7.28.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md b/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md -index 884ef28e2..749dedf20 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.56.0 - --- - - # NAME -@@ -35,6 +36,8 @@ may or may not do it. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.56.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md -index 858c59e5e..4629bb632 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md -@@ -1,7 +1,7 @@ - --- - c: Copyright (C) Daniel Stenberg, , et al. - SPDX-License-Identifier: curl --Title: CURLOPT_SSH_KEYDATA -+Title: CURLOPT_SSH_HOSTKEYDATA - Section: 3 - Source: libcurl - See-also: -@@ -9,6 +9,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.84.0 - --- - - # NAME -@@ -32,6 +33,8 @@ the callback set with CURLOPT_SSH_HOSTKEYFUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -63,9 +66,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES -+ -+Works only with the libssh2 backend. - --Added in 7.84.0, works only with libssh2 backend. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md -index 2c12fb877..ecaa078a1 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.84.0 - --- - - # NAME -@@ -58,6 +59,8 @@ the host key is rejected, the connection is canceled. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -88,9 +91,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES -+ -+Work only with the libssh2 backend. - --Added in 7.84.0 , work only with libssh2 backend. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md -index fd045f9f3..3ad3a63fe 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md -@@ -12,6 +12,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.17.1 - --- - - # NAME -@@ -39,10 +40,15 @@ CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3) instead. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +66,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.17.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md -index 15e12d3f6..cd8d6ecdb 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md -@@ -11,6 +11,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.80.0 - --- - - # NAME -@@ -32,10 +33,18 @@ Pass a char pointer pointing to a string containing a Base64-encoded SHA256 - hash of the remote host's public key. The transfer fails if the given hash - does not match the hash the remote host provides. - -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,11 +62,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES - --Added in 7.80.0 - Requires the libssh2 backend. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md b/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md -index 8e35a9315..64d98c41f 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.19.6 - --- - - # NAME -@@ -33,6 +34,8 @@ callback set with CURLOPT_SSH_KEYFUNCTION(3). - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md -index ce71cf419..3d815abdb 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.19.6 - --- - - # NAME -@@ -33,7 +34,7 @@ enum curl_khstat { - - enum curl_khmatch { - CURLKHMATCH_OK, /* match */ -- CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ -+ CURLKHMATCH_MISMATCH, /* host found, key mismatch */ - CURLKHMATCH_MISSING, /* no matching host/key found */ - }; - -@@ -109,6 +110,8 @@ up from scratch again. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -142,9 +145,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md b/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md -index 86828c0a6..8b7705b4b 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.19.6 - --- - - # NAME -@@ -36,10 +37,15 @@ behavior on host and key matches and mismatches. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md b/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md -index fc24eb00b..fe7e5207e 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.16.1 - --- - - # NAME -@@ -47,6 +48,8 @@ option. - - As explained above - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -65,9 +68,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md b/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md -index 0c27b7edf..f6d2fb3c1 100644 ---- a/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md -+++ b/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md -@@ -10,6 +10,7 @@ See-also: - Protocol: - - SFTP - - SCP -+Added-in: 7.16.1 - --- - - # NAME -@@ -43,6 +44,8 @@ option. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,10 +63,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - The "" trick was added in 7.26.0 - -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or -diff --git a/docs/libcurl/opts/CURLOPT_SSLCERT.md b/docs/libcurl/opts/CURLOPT_SSLCERT.md -index f7d3b28f1..8669e9505 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLCERT.md -+++ b/docs/libcurl/opts/CURLOPT_SSLCERT.md -@@ -17,6 +17,7 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -+Added-in: 7.1 - --- - - # NAME -@@ -47,13 +48,12 @@ in order to avoid confusion with a nickname. - certificate store. (You can import *PFX* to a store first). You can use - "\\\\\\\" to refer to a certificate - in the system certificates store, for example, --**"CurrentUser\\MY\\934a7ac6f8a5d579285a74fa"**. The thumbprint is usually a --SHA-1 hex string which you can see in certificate details. Following store --locations are supported: **CurrentUser**, **LocalMachine**, --**CurrentService**, **Services**, **CurrentUserGroupPolicy**, --**LocalMachineGroupPolicy**, **LocalMachineEnterprise**. Schannel also support --P12 certificate file, with the string `P12` specified with --CURLOPT_SSLCERTTYPE(3). -+**"CurrentUser\\MY\\934a7ac6f8a5d5"**. The thumbprint is usually a SHA-1 hex -+string which you can see in certificate details. Following store locations are -+supported: **CurrentUser**, **LocalMachine**, **CurrentService**, -+**Services**, **CurrentUserGroupPolicy**, **LocalMachineGroupPolicy**, -+**LocalMachineEnterprise**. Schannel also support P12 certificate file, with -+the string `P12` specified with CURLOPT_SSLCERTTYPE(3). - - When using a client certificate, you most likely also need to provide a - private key with CURLOPT_SSLKEY(3). -@@ -61,10 +61,15 @@ private key with CURLOPT_SSLKEY(3). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -83,9 +88,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md b/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md -index debbcd160..696344a90 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md -+++ b/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md -@@ -16,6 +16,7 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -+Added-in: 7.9.3 - --- - - # NAME -@@ -37,16 +38,21 @@ the format of your certificate. - - Supported formats are "PEM" and "DER", except with Secure Transport or - Schannel. OpenSSL (versions 0.9.3 and later), Secure Transport (on iOS 5 or --later, or OS X 10.7 or later) and Schannel support "P12" for PKCS#12-encoded --files. -+later, or macOS 10.7 or later) and Schannel support "P12" for PKCS#12-encoded -+files. GnuTLS supports P12 starting with curl 8.11.0. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL restores back to internal default. -+ - # DEFAULT - - "PEM" - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled. Added in 7.9.3 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md b/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md -index 80a50c72f..fb1cc62fa 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md -@@ -15,6 +15,8 @@ TLS-backend: - - Secure Transport - - Schannel - - mbedTLS -+ - wolfSSL -+Added-in: 7.71.0 - --- - - # NAME -@@ -49,6 +51,8 @@ expects a filename as input. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -75,10 +79,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL, Secure Transport, --Schannel and mbedTLS (since 7.78.0) backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLENGINE.md b/docs/libcurl/opts/CURLOPT_SSLENGINE.md -index 44cd44cbe..9bddf39ff 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLENGINE.md -+++ b/docs/libcurl/opts/CURLOPT_SSLENGINE.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.9.3 - --- - - # NAME -@@ -34,10 +35,15 @@ identifier for the crypto engine you want to use for your private key. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Only if OpenSSL is built with engine support. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md b/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md -index 963b9c1af..72e908b76 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md -+++ b/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md -@@ -11,6 +11,7 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+Added-in: 7.9.3 - --- - - # NAME -@@ -36,6 +37,8 @@ This option has no effect unless set after CURLOPT_SSLENGINE(3). - - None - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Only if the SSL backend is OpenSSL built with engine support. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLKEY.md b/docs/libcurl/opts/CURLOPT_SSLKEY.md -index f87e8eb67..13363ce2b 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLKEY.md -+++ b/docs/libcurl/opts/CURLOPT_SSLKEY.md -@@ -15,6 +15,7 @@ TLS-backend: - - mbedTLS - - Schannel - - wolfSSL -+Added-in: 7.9.3 - --- - - # NAME -@@ -35,17 +36,22 @@ Pass a pointer to a null-terminated string as parameter. The string should be - the filename of your private key. The default format is "PEM" and can be - changed with CURLOPT_SSLKEYTYPE(3). - --(Windows, iOS and Mac OS X) This option is ignored by Secure Transport and -+(Windows, iOS and macOS) This option is ignored by Secure Transport and - Schannel SSL backends because they expect the private key to be already present - in the key-chain or PKCS#12 file containing the certificate. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md b/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md -index 182f77748..0f0106dc3 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md -+++ b/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md -@@ -14,6 +14,7 @@ TLS-backend: - - OpenSSL - - BearSSL - - wolfSSL -+Added-in: 7.9.3 - --- - - # NAME -@@ -41,10 +42,15 @@ currently does not work because of a bug in OpenSSL. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to internal default. -+ - # DEFAULT - - "PEM" - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md b/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md -index 4ef3b0751..bedf2d33c 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md -+++ b/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md -@@ -11,6 +11,8 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -+ - wolfSSL -+Added-in: 7.71.0 - --- - - # NAME -@@ -43,6 +45,8 @@ filename as input. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -77,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.71.0. This option is supported by the OpenSSL backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSLVERSION.md b/docs/libcurl/opts/CURLOPT_SSLVERSION.md -index c483b8268..fd05eb416 100644 ---- a/docs/libcurl/opts/CURLOPT_SSLVERSION.md -+++ b/docs/libcurl/opts/CURLOPT_SSLVERSION.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -71,10 +72,11 @@ TLS v1.2 or later (Added in 7.34.0) - - TLS v1.3 or later (Added in 7.52.0) - -+## -+ - The maximum TLS version can be set by using *one* of the - CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the - CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros. --The MAX macros are not supported for WolfSSL. - - ## CURL_SSLVERSION_MAX_DEFAULT - -@@ -103,6 +105,8 @@ The flag defines maximum supported TLS version as TLS v1.2. - The flag defines maximum supported TLS version as TLS v1.3. - (Added in 7.54.0) - -+## -+ - In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were - documented to allow *only* the specified TLS version, but behavior was - inconsistent depending on the TLS library. -@@ -111,6 +115,8 @@ inconsistent depending on the TLS library. - - CURL_SSLVERSION_DEFAULT - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -129,15 +135,23 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --SSLv2 and SSLv3 are refused completely since curl 7.77.0 -+# HISTORY - - SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may - vary depending on which backend libcurl has been built to use. - - SSLv3 is disabled by default since 7.39.0. - -+SSLv2 and SSLv3 are refused completely since curl 7.77.0 -+ -+Since 8.10.0 wolfSSL is fully supported. Before 8.10.0 the MAX macros were not -+supported with wolfSSL and the other macros did not set a minimum, but -+restricted the TLS version to only the specified one. -+ -+Rustls support added in 8.10.0. -+ -+# %AVAILABILITY% -+ - # RETURN VALUE - - Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md -index 3bf09d8db..df57c837c 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md -@@ -18,7 +18,9 @@ TLS-backend: - - Schannel - - Secure Transport - - wolfSSL -- - GnuTLS -+ - mbedTLS -+ - rustls -+Added-in: 7.9 - --- - - # NAME -@@ -36,24 +38,17 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_CIPHER_LIST, char *list); - # DESCRIPTION - - Pass a char pointer, pointing to a null-terminated string holding the list of --ciphers to use for the SSL connection. The list must be syntactically correct, --it consists of one or more cipher strings separated by colons. Commas or --spaces are also acceptable separators but colons are normally used, !, - and --+ can be used as operators. -+cipher suites to use for the TLS 1.2 (1.1, 1.0) connection. The list must -+be syntactically correct, it consists of one or more cipher suite strings -+separated by colons. - --For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**, --**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally set when --you compile OpenSSL. -+For setting TLS 1.3 ciphers see CURLOPT_TLS13_CIPHERS(3). - --For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**, --**AES256-SHA:AES256-SHA256**, etc. -- --For BearSSL, valid examples of cipher lists include --**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using --IANA names --**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**, --etc. With BearSSL you do not add/remove ciphers. If one uses this option then --all known ciphers are disabled and only those passed in are enabled. -+A valid example of a cipher list is: -+~~~ -+"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" -+"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305" -+~~~ - - For Schannel, you can use this option to set algorithms but not specific - cipher suites. Refer to the ciphers lists document for algorithms. -@@ -65,9 +60,14 @@ Find more details about cipher lists on this URL: - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --NULL, use internal default -+NULL, use built-in list -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -78,20 +78,29 @@ int main(void) - if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "TLSv1"); -+ curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, -+ "ECDHE-ECDSA-CHACHA20-POLY1305:" -+ "ECDHE-RSA-CHACHA20-POLY1305"); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - } - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+OpenSSL support added in 7.9. -+wolfSSL support added in 7.53.0. -+Schannel support added in 7.61.0. -+Secure Transport support added in 7.77.0. -+BearSSL support added in 7.83.0. -+mbedTLS support added in 8.8.0. -+Rustls support added in 8.10.0. - --Added in 7.9, in 7.83.0 for BearSSL -+Since curl 8.10.0 returns CURLE_NOT_BUILT_IN when not supported. - --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - --Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or --CURLE_OUT_OF_MEMORY if there was insufficient heap space. -+Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise. -diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md -index 5e74f5a36..2dcdd57e1 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md -@@ -14,6 +14,7 @@ TLS-backend: - - wolfSSL - - mbedTLS - - BearSSL -+Added-in: 7.10.6 - --- - - # NAME -@@ -38,6 +39,8 @@ parameter. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -113,11 +116,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Added in 7.11.0 for OpenSSL, in 7.42.0 for wolfSSL, in 7.54.0 for mbedTLS, - in 7.83.0 in BearSSL. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - CURLE_OK if supported; or an error such as: -diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md -index 64732c1a7..f461209bc 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md -@@ -5,9 +5,12 @@ Title: CURLOPT_SSL_CTX_FUNCTION - Section: 3 - Source: libcurl - See-also: -+ - CURLOPT_CA_CACHE_TIMEOUT (3) -+ - CURLOPT_CAINFO (3) -+ - CURLOPT_CAINFO_BLOB (3) - - CURLOPT_SSL_CTX_DATA (3) -+ - CURLOPT_SSL_VERIFYHOST (3) - - CURLOPT_SSL_VERIFYPEER (3) -- - CURLOPT_CAINFO (3) - Protocol: - - TLS - TLS-backend: -@@ -15,6 +18,7 @@ TLS-backend: - - wolfSSL - - mbedTLS - - BearSSL -+Added-in: 7.10.6 - --- - - # NAME -@@ -78,10 +82,16 @@ callback function has returned. Your application must not assume that it can - keep using the SSL context or data derived from it once this function is - completed. - -+For libcurl builds using TLS backends that support CA caching and -+CURLOPT_CA_CACHE_TIMEOUT(3) is not set to zero, multiple calls to this -+callback may be done with the same CA store in memory. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -157,10 +167,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --OpenSSL (added in 7.11.0), wolfSSL (added in 7.42.0), mbedTLS (added in --7.54.0) or BearSSL (added in 7.83.0) -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md -index e68ac37cd..6256e25f7 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - wolfSSL -+Added-in: 7.73.0 - --- - - # NAME -@@ -24,19 +25,27 @@ CURLOPT_SSL_EC_CURVES - key exchange curves - ~~~c - #include - --CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_EC_CURVES, char *alg_list); -+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_EC_CURVES, char *list); - ~~~ - - # DESCRIPTION - --Pass a string as parameter with a colon delimited list of (EC) algorithms. This --option defines the client's key exchange algorithms in the SSL handshake (if --the SSL backend libcurl is built to use supports it). -+Pass a string as parameter with a colon delimited list of Elliptic curve (EC) -+algorithms. This option defines the client's key exchange algorithms in the -+SSL handshake (if the SSL backend libcurl is built to use supports it). -+ -+The application does not have to keep the string around after setting this -+option. -+ -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore back to internal default. - - # DEFAULT - - "", embedded in SSL backend - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.73.0. Supported by the OpenSSL backend. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md -index f53a6fc8d..e521c543d 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md -@@ -11,6 +11,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.36.0 - --- - - # NAME -@@ -35,6 +36,8 @@ is built to use supports it), which can be used to negotiate http2. - - 1, enabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,9 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.36.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md -index 26c79f33d..65ade8bd4 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md -@@ -11,6 +11,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.36.0 - --- - - # NAME -@@ -27,7 +28,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_ENABLE_NPN, long npn); - - # DESCRIPTION - --Deprecated in 7.86.0. Setting this option has no function. -+Deprecated since 7.86.0. Setting this option has no function. - - Pass a long as parameter, 0 or 1 where 1 is for enable and 0 for disable. This - option enables/disables NPN in the SSL handshake (if the SSL backend libcurl -@@ -37,6 +38,8 @@ is built to use supports it), which can be used to negotiate http2. - - 1, enabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,9 +56,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# DEPRECATED -+ -+Deprecated since 7.86.0. - --Added in 7.36.0. Deprecated in 7.86.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md -index 7758f0d90..83b6b69da 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md -@@ -10,6 +10,7 @@ Protocol: - - TLS - TLS-backend: - - Secure Transport -+Added-in: 7.42.0 - --- - - # NAME -@@ -37,6 +38,8 @@ when performing a full handshake. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,10 +54,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.42.0. This option is currently only supported by the Secure --Transport (on iOS 7.0 or later, or OS X 10.9 or later) TLS backend. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md -index ddf278e6f..f789a8b52 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.25.0 - --- - - # NAME -@@ -85,10 +86,21 @@ certificate that supports client authentication in the OS certificate store it - could be a privacy violation and unexpected. - (Added in 7.77.0) - -+## CURLSSLOPT_EARLYDATA -+ -+Tell libcurl to try sending application data as TLS1.3 early data. This option -+is only supported for GnuTLS. This option works on a best effort basis, -+in cases when it wasn't possible to send early data the request is resent -+normally post-handshake. -+This option does not work when using QUIC. -+(Added in 8.11.0) -+ - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -107,9 +119,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.25.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md b/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md -index 364eb0409..369070269 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md -@@ -13,6 +13,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.16.0 - --- - - # NAME -@@ -40,6 +41,8 @@ wild that may require you to disable this in order for you to succeed. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -49,7 +52,7 @@ int main(void) - if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- /* switch off session-id use! */ -+ /* switch off session-id use */ - curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.16.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md -index f432fecbd..30b1525fe 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md -@@ -12,6 +12,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.8.1 - --- - - # NAME -@@ -28,40 +29,27 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYHOST, long verify); - - # DESCRIPTION - --Pass a long as parameter specifying what to *verify*. -+Pass a long set to 2L to make libcurl verify the host in the server's TLS -+certificate. - --This option determines whether libcurl verifies that the server cert is for --the server it is known as. -+When negotiating a TLS connection, the server sends a certificate indicating -+its identity. - --When negotiating TLS and SSL connections, the server sends a certificate --indicating its identity. -+When CURLOPT_SSL_VERIFYHOST(3) is set to 1 or 2, the server certificate must -+indicate that it was made for the hostname or address curl connects to, or the -+connection fails. Simply put, it means it has to have the same name in the -+certificate as is used in the URL you operate against. - --When CURLOPT_SSL_VERIFYHOST(3) is 2, that certificate must indicate that --the server is the server to which you meant to connect, or the connection --fails. Simply put, it means it has to have the same name in the certificate as --is in the URL you operate against. -- --Curl considers the server the intended one when the Common Name field or a -+curl considers the server the intended one when the Common Name field or a - Subject Alternate Name field in the certificate matches the hostname in the --URL to which you told Curl to connect. -- --If *verify* value is set to 1: -- --In 7.28.0 and earlier: treated as a debug option of some sorts, not supported --anymore due to frequently leading to programmer mistakes. -+URL to which you told curl to connect. - --From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return --an error and leaving the flag untouched. -+When the *verify* value is 0, the connection succeeds regardless of the names -+in the certificate. Use that ability with caution, - --From 7.66.0: treats 1 and 2 the same. -- --When the *verify* value is 0, the connection succeeds regardless of the --names in the certificate. Use that ability with caution! -- --The default value for this option is 2. -- --This option controls checking the server's certificate's claimed identity. --The server could be lying. To control lying, see CURLOPT_SSL_VERIFYPEER(3). -+This option controls checking the server's certificate's claimed identity. The -+separate CURLOPT_SSL_VERIFYPEER(3) options enables/disables verification that -+the certificate is signed by a trusted Certificate Authority. - - WARNING: disabling verification of the certificate allows bad guys to - man-in-the-middle the communication without you knowing it. Disabling -@@ -74,18 +62,31 @@ HSTS and Alt-Svc information to be stored and used subsequently. Disabling - certificate verification can make libcurl trust and use such information from - malicious servers. - -+# MATCHING -+ -+A certificate can have the name as a wildcard. The only asterisk (`*`) must -+then be the left-most character and it must be followed by a period. The -+wildcard must further contain more than one period as it cannot be set for a -+top-level domain. -+ -+A certificate can be set for a numerical IP address (IPv4 or IPv6), but then -+it should be a Subject Alternate Name kind and its type should correctly -+identify the field as an IP address. -+ - # LIMITATIONS - --Secure Transport: If *verify* value is 0, then SNI is also disabled. SNI is --a TLS extension that sends the hostname to the server. The server may use that -+Secure Transport: If *verify* value is 0, then SNI is also disabled. SNI is a -+TLS extension that sends the hostname to the server. The server may use that - information to do such things as sending back a specific certificate for the --hostname, or forwarding the request to a specific origin server. Some hostnames --may be inaccessible if SNI is not sent. -+hostname, or forwarding the request to a specific origin server. Some -+hostnames may be inaccessible if SNI is not sent. - - # DEFAULT - - 2 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -103,12 +104,18 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# %AVAILABILITY% - --If built TLS enabled. -+# HISTORY -+ -+In 7.28.0 and earlier: the value 1 was treated as a debug option of some -+sorts, not supported anymore due to frequently leading to programmer mistakes. -+ -+From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return -+an error and leaving the flag untouched. -+ -+From 7.66.0: libcurl treats 1 and 2 to this option the same. - - # RETURN VALUE - - Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not. -- --If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned. -diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md -index 214da41cf..4d4bf7c6b 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md -@@ -15,6 +15,7 @@ Protocol: - - TLS - TLS-backend: - - All -+Added-in: 7.4.2 - --- - - # NAME -@@ -72,6 +73,8 @@ malicious servers. - - 1 - enabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -89,9 +92,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --If built TLS enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md -index 7f6b1a019..aa8653d1c 100644 ---- a/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md -+++ b/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.41.0 - --- - - # NAME -@@ -41,6 +42,8 @@ extension, the verification fails. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -50,7 +53,7 @@ int main(void) - if(curl) { - CURLcode res; - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); -- /* ask for OCSP stapling! */ -+ /* ask for OCSP stapling */ - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); -@@ -58,10 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.41.0. This option is currently only supported by the OpenSSL and --GnuTLS TLS backends. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_STDERR.md b/docs/libcurl/opts/CURLOPT_STDERR.md -index f38aba25e..368944334 100644 ---- a/docs/libcurl/opts/CURLOPT_STDERR.md -+++ b/docs/libcurl/opts/CURLOPT_STDERR.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_VERBOSE (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -38,6 +39,8 @@ application. A work-around is to instead use CURLOPT_DEBUGFUNCTION(3). - - stderr - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md -index 7342f3bcf..1429de1f8 100644 ---- a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md -+++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_STREAM_WEIGHT (3) - Protocol: - - HTTP -+Added-in: 7.46.0 - --- - - # NAME -@@ -47,6 +48,8 @@ option to have an actual effect. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,14 +64,12 @@ int main(void) - curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); - curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS, curl); - -- /* then add both to a multi handle and transfer them! */ -+ /* then add both to a multi handle and transfer them */ - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.46.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md -index 8d109fb19..bddfead62 100644 ---- a/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md -+++ b/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_STREAM_WEIGHT (3) - Protocol: - - HTTP -+Added-in: 7.46.0 - --- - - # NAME -@@ -50,6 +51,8 @@ option to have an actual effect. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,14 +67,12 @@ int main(void) - curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); - curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS_E, curl); - -- /* then add both to a multi handle and transfer them! */ -+ /* then add both to a multi handle and transfer them */ - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.46.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md b/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md -index fdd2a1840..57088a790 100644 ---- a/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md -+++ b/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_STREAM_DEPENDS_E (3) - Protocol: - - HTTP -+Added-in: 7.46.0 - --- - - # NAME -@@ -47,8 +48,9 @@ streams). - - # DEFAULT - --If nothing is set, the HTTP/2 protocol itself uses its own default which is --16. -+16 -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -65,14 +67,12 @@ int main(void) - curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two"); - curl_easy_setopt(curl2, CURLOPT_STREAM_WEIGHT, 20L); - -- /* then add both to a multi handle and transfer them! */ -+ /* then add both to a multi handle and transfer them */ - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.46.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md b/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md -index b6357b503..b05824630 100644 ---- a/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md -+++ b/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_PROXY (3) - Protocol: - - All -+Added-in: 7.54.0 - --- - - # NAME -@@ -70,6 +71,8 @@ Content-Type: application/json - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -92,9 +95,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.54.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md b/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md -index 42b44a567..1f8f5d4a5 100644 ---- a/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md -+++ b/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md -@@ -7,7 +7,8 @@ Source: libcurl - See-also: - - CURLOPT_SSL_FALSESTART (3) - Protocol: -- - All -+ - TCP -+Added-in: 7.49.0 - --- - - # NAME -@@ -37,6 +38,8 @@ Fast Open is also known to be problematic on or across certain networks. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -51,10 +54,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# NOTES -+ -+This option is only supported on Linux and macOS 10.11 or later. - --Added in 7.49.0. This option is currently only supported on Linux and macOS --10.11 or later. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md -index e9e80ac6a..3d9da660d 100644 ---- a/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md -+++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md -@@ -9,8 +9,10 @@ See-also: - - CURLOPT_MAX_RECV_SPEED_LARGE (3) - - CURLOPT_TCP_KEEPIDLE (3) - - CURLOPT_TCP_KEEPINTVL (3) -+ - CURLOPT_TCP_KEEPCNT (3) - Protocol: -- - All -+ - TCP -+Added-in: 7.25.0 - --- - - # NAME -@@ -29,14 +31,16 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPALIVE, long probe); - - Pass a long. If set to 1, TCP keepalive probes are used. The delay and - frequency of these probes can be controlled by the --CURLOPT_TCP_KEEPIDLE(3) and CURLOPT_TCP_KEEPINTVL(3) options, --provided the operating system supports them. Set to 0 (default behavior) to --disable keepalive probes -+CURLOPT_TCP_KEEPIDLE(3), CURLOPT_TCP_KEEPINTVL(3), and CURLOPT_TCP_KEEPCNT(3) -+options, provided the operating system supports them. Set to 0 (default behavior) -+to disable keepalive probes. - - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,14 +59,15 @@ int main(void) - /* interval time between keep-alive probes: 60 seconds */ - curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); - -+ /* maximum number of keep-alive probes: 3 */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L); -+ - curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.25.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md -new file mode 100644 -index 000000000..5a03f3cff ---- /dev/null -+++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md -@@ -0,0 +1,74 @@ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Title: CURLOPT_TCP_KEEPCNT -+Section: 3 -+Source: libcurl -+See-also: -+ - CURLOPT_TCP_KEEPALIVE (3) -+ - CURLOPT_TCP_KEEPIDLE (3) -+ - CURLOPT_TCP_KEEPINTVL (3) -+Protocol: -+ - TCP -+Added-in: 8.9.0 -+--- -+ -+# NAME -+ -+CURLOPT_TCP_KEEPCNT - Maximum number of TCP keep-alive probes -+ -+# SYNOPSIS -+ -+~~~c -+#include -+ -+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPCNT, long cnt); -+~~~ -+ -+# DESCRIPTION -+ -+Pass a long. Sets the number of probes to send before dropping -+the connection. Not all operating systems support this option. -+(Added in 8.9.0) -+ -+The maximum value this option accepts is INT_MAX or whatever your -+system allows. -+Any larger value is capped to this amount. -+ -+# DEFAULT -+ -+9 -+ -+# %PROTOCOLS% -+ -+# EXAMPLE -+ -+~~~c -+int main(void) -+{ -+ CURL *curl = curl_easy_init(); -+ if(curl) { -+ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); -+ -+ /* enable TCP keep-alive for this transfer */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); -+ -+ /* set keep-alive idle time to 120 seconds */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); -+ -+ /* interval time between keep-alive probes: 60 seconds */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); -+ -+ /* maximum number of keep-alive probes: 3 */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L); -+ -+ curl_easy_perform(curl); -+ } -+} -+~~~ -+ -+# %AVAILABILITY% -+ -+# RETURN VALUE -+ -+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. -diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md -index 5f8841747..370ace4a2 100644 ---- a/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md -+++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md -@@ -7,8 +7,10 @@ Source: libcurl - See-also: - - CURLOPT_TCP_KEEPALIVE (3) - - CURLOPT_TCP_KEEPINTVL (3) -+ - CURLOPT_TCP_KEEPCNT (3) - Protocol: -- - All -+ - TCP -+Added-in: 7.25.0 - --- - - # NAME -@@ -36,6 +38,8 @@ this amount. - - 60 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,14 +58,15 @@ int main(void) - /* interval time between keep-alive probes: 60 seconds */ - curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); - -+ /* maximum number of keep-alive probes: 3 */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L); -+ - curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.25.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md -index 405b6ec82..9d0ebc7a8 100644 ---- a/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md -+++ b/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md -@@ -7,8 +7,10 @@ Source: libcurl - See-also: - - CURLOPT_TCP_KEEPALIVE (3) - - CURLOPT_TCP_KEEPIDLE (3) -+ - CURLOPT_TCP_KEEPCNT (3) - Protocol: -- - All -+ - TCP -+Added-in: 7.25.0 - --- - - # NAME -@@ -35,6 +37,8 @@ this amount. - - 60 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -53,14 +57,15 @@ int main(void) - /* interval time between keep-alive probes: 60 seconds */ - curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); - -+ /* maximum number of keep-alive probes: 3 */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L); -+ - curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md b/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md -index a5b15abbf..6b30b5465 100644 ---- a/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md -+++ b/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md -@@ -9,7 +9,8 @@ See-also: - - CURLOPT_SOCKOPTFUNCTION (3) - - CURLOPT_TCP_KEEPALIVE (3) - Protocol: -- - All -+ - TCP -+Added-in: 7.11.2 - --- - - # NAME -@@ -45,6 +46,8 @@ overdone. - - 1 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+The default was changed to 1 from 0 in 7.50.2. - --Always. The default was changed to 1 from 0 in 7.50.2. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md b/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md -index 9e45df837..85a92f8da 100644 ---- a/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_QUOTE (3) - Protocol: - - TELNET -+Added-in: 7.7 - --- - - # NAME -@@ -31,10 +32,18 @@ negotiations. The variables should be in the format \. libcurl - supports the options **TTYPE**, **XDISPLOC** and **NEW_ENV**. See the TELNET - standard for details. - -+Using this option multiple times makes the last set list override the previous -+ones. Set it to NULL to disable its use again. -+ -+libcurl does not copy the list, it needs to be kept around until after the -+transfer has completed. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -55,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with TELNET -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md b/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md -index 1b5c9ae6f..ab85fe45f 100644 ---- a/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md -+++ b/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_MAXFILESIZE (3) - Protocol: - - TFTP -+Added-in: 7.19.4 - --- - - # NAME -@@ -35,6 +36,8 @@ is used. - - 512 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -52,9 +55,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md b/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md -index 953702696..098ee3944 100644 ---- a/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_TFTP_BLKSIZE (3) - Protocol: - - TFTP -+Added-in: 7.48.0 - --- - - # NAME -@@ -35,6 +36,8 @@ CURLOPT_TFTP_BLKSIZE(3) is ignored. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +70,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.48.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md -index b4bdb4fa2..43c679bd6 100644 ---- a/docs/libcurl/opts/CURLOPT_TIMECONDITION.md -+++ b/docs/libcurl/opts/CURLOPT_TIMECONDITION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_TIMEVALUE (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -39,6 +40,8 @@ option can be used after a transfer to learn if a zero-byte successful - - CURL_TIMECOND_NONE (0) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +64,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TIMEOUT.md b/docs/libcurl/opts/CURLOPT_TIMEOUT.md -index c35bb4076..d5b396cec 100644 ---- a/docs/libcurl/opts/CURLOPT_TIMEOUT.md -+++ b/docs/libcurl/opts/CURLOPT_TIMEOUT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TIMEOUT_MS (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -54,12 +55,14 @@ With CURLOPT_CONNECTTIMEOUT(3) set to 4 and CURLOPT_TIMEOUT(3) set - to 2, the operation can never last longer than 2 seconds. - - This option may cause libcurl to use the SIGALRM signal to timeout system --calls on builds not using asynch DNS. In unix-like systems, this might cause -+calls on builds not using asynch DNS. In Unix-like systems, this might cause - signals to be used unless CURLOPT_NOSIGNAL(3) is set. - - # DEFAULT - --Default timeout is 0 (zero) which means it never times out during transfer. -+0 (zero) which means it never times out during transfer. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -78,9 +81,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md b/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md -index 8f13480d3..e02261d5b 100644 ---- a/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md -+++ b/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_TIMEOUT (3) - Protocol: - - All -+Added-in: 7.16.2 - --- - - # NAME -@@ -34,7 +35,9 @@ See CURLOPT_TIMEOUT(3) for details. - - # DEFAULT - --Default timeout is 0 (zero) which means it never times out during transfer. -+0 (zero) which means it never times out during transfer. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -53,9 +56,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TIMEVALUE.md b/docs/libcurl/opts/CURLOPT_TIMEVALUE.md -index 5558e6d17..ef9b9dab1 100644 ---- a/docs/libcurl/opts/CURLOPT_TIMEVALUE.md -+++ b/docs/libcurl/opts/CURLOPT_TIMEVALUE.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_TIMEVALUE_LARGE (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -29,7 +30,7 @@ Pass a long *val* as parameter. This should be the time counted as seconds - since 1 Jan 1970, and the time is used in a condition as specified with - CURLOPT_TIMECONDITION(3). - --On systems with 32 bit 'long' variables (such as Windows), this option cannot -+On systems with 32-bit 'long' variables (such as Windows), this option cannot - set dates beyond the year 2038. Consider CURLOPT_TIMEVALUE_LARGE(3) - instead. - -@@ -37,6 +38,8 @@ instead. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -58,9 +61,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md b/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md -index cd16c7589..9ae16e4e0 100644 ---- a/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md -+++ b/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_TIMEVALUE (3) - Protocol: - - HTTP -+Added-in: 7.59.0 - --- - - # NAME -@@ -31,14 +32,16 @@ Pass a curl_off_t *val* as parameter. This should be the time counted as - seconds since 1 Jan 1970, and the time is used in a condition as specified - with CURLOPT_TIMECONDITION(3). - --The difference between this option and CURLOPT_TIMEVALUE(3) is the type --of the argument. On systems where 'long' is only 32 bit wide, this option has --to be used to set dates beyond the year 2038. -+The difference between this option and CURLOPT_TIMEVALUE(3) is the type of the -+argument. On systems where 'long' is only 32 bits wide, this option has to be -+used to set dates beyond the year 2038. - - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.59.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md -index 779497243..d2c6226d5 100644 ---- a/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md -+++ b/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md -@@ -15,8 +15,11 @@ Protocol: - - TLS - TLS-backend: - - OpenSSL -- - rustls - - Schannel -+ - wolfSSL -+ - mbedTLS -+ - rustls -+Added-in: 7.61.0 - --- - - # NAME -@@ -38,21 +41,28 @@ cipher suites to use for the TLS 1.3 connection. The list must be - syntactically correct, it consists of one or more cipher suite strings - separated by colons. - -+For setting TLS 1.2 (1.1, 1.0) ciphers see CURLOPT_SSL_CIPHER_LIST(3). -+ -+A valid example of a cipher list is: -+~~~c -+"TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256" -+~~~ -+ - Find more details about cipher lists on this URL: - - https://curl.se/docs/ssl-ciphers.html - --This option is currently used only when curl is built to use OpenSSL 1.1.1 or --later, or Schannel. If you are using a different SSL backend you can try --setting TLS 1.3 cipher suites by using the CURLOPT_SSL_CIPHER_LIST(3) --option. -- - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to internal default. -+ - # DEFAULT - --NULL, use internal default -+NULL, use internal built-in -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -71,11 +81,19 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+OpenSSL support added in 7.61.0, available when built with OpenSSL \>= 1.1.1. -+Schannel support added in 7.85.0. -+LibreSSL support added in 8.3.0, available when built with LibreSSL \>= 3.4.1. -+wolfSSL support added in 8.10.0. -+mbedTLS support added in 8.10.0, available when built with mbedTLS \>= 3.6.0. -+Rustls support added in 8.10.0. - --Added in 7.61.0 for OpenSSL. Available when built with OpenSSL \>= 1.1.1. -+Before curl 8.10.0 with mbedTLS or wolfSSL, TLS 1.3 cipher suites were set -+by using the CURLOPT_SSL_CIPHER_LIST(3) option. - --Added in 7.85.0 for Schannel. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md -index 6a9a83829..2548aa73d 100644 ---- a/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md -+++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md -@@ -13,6 +13,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.21.4 - --- - - # NAME -@@ -31,18 +32,23 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_PASSWORD, char *pwd); - - Pass a char pointer as parameter, which should point to the null-terminated - password to use for the TLS authentication method specified with the --CURLOPT_TLSAUTH_TYPE(3) option. Requires that the --CURLOPT_TLSAUTH_USERNAME(3) option also be set. -+CURLOPT_TLSAUTH_TYPE(3) option. Requires that the CURLOPT_TLSAUTH_USERNAME(3) -+option also be set. - - The application does not have to keep the string around after setting this - option. - --This feature relies in TLS SRP which does not work with TLS 1.3. -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+This feature relies on TLS SRP which does not work with TLS 1.3. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -61,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.4, with the OpenSSL and GnuTLS backends only -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md -index 0611334e4..719095cf5 100644 ---- a/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md -+++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md -@@ -12,6 +12,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.21.4 - --- - - # NAME -@@ -31,16 +32,18 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_TYPE, char *type); - Pass a pointer to a null-terminated string as parameter. The string should be - the method of the TLS authentication. Supported method is "SRP". - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to restore to internal default. -+ -+The application does not have to keep the string around after setting this -+option. -+ - ## SRP - - TLS-SRP authentication. Secure Remote Password authentication for TLS is - defined in RFC 5054 and provides mutual authentication if both sides have a - shared secret. To use TLS-SRP, you must also set the --CURLOPT_TLSAUTH_USERNAME(3) and CURLOPT_TLSAUTH_PASSWORD(3) --options. -- --The application does not have to keep the string around after setting this --option. -+CURLOPT_TLSAUTH_USERNAME(3) and CURLOPT_TLSAUTH_PASSWORD(3) options. - - TLS SRP does not work with TLS 1.3. - -@@ -48,6 +51,8 @@ TLS SRP does not work with TLS 1.3. - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -66,10 +71,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this --to work. Added in 7.21.4 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md b/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md -index c69ac8167..9af68650b 100644 ---- a/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md -+++ b/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md -@@ -12,6 +12,7 @@ Protocol: - TLS-backend: - - OpenSSL - - GnuTLS -+Added-in: 7.21.4 - --- - - # NAME -@@ -30,18 +31,23 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_USERNAME, char *user); - - Pass a char pointer as parameter, which should point to the null-terminated - username to use for the TLS authentication method specified with the --CURLOPT_TLSAUTH_TYPE(3) option. Requires that the --CURLOPT_TLSAUTH_PASSWORD(3) option also be set. -+CURLOPT_TLSAUTH_TYPE(3) option. Requires that the CURLOPT_TLSAUTH_PASSWORD(3) -+option also be set. - - The application does not have to keep the string around after setting this - option. - --This feature relies in TLS SRP which does not work with TLS 1.3. -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ -+This feature relies on TLS SRP which does not work with TLS 1.3. - - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +66,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.4, with the OpenSSL and GnuTLS backends only -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TRAILERDATA.md b/docs/libcurl/opts/CURLOPT_TRAILERDATA.md -index 2eceb16e7..bcc675303 100644 ---- a/docs/libcurl/opts/CURLOPT_TRAILERDATA.md -+++ b/docs/libcurl/opts/CURLOPT_TRAILERDATA.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - HTTP -+Added-in: 7.64.0 - --- - - # NAME -@@ -31,6 +32,8 @@ Data pointer to be passed to the HTTP trailer callback function. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -48,9 +51,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --This option was added in curl 7.64.0 and is present if HTTP support is enabled -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md b/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md -index a6cd7fa5f..9c06a598c 100644 ---- a/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - HTTP -+Added-in: 7.64.0 - --- - - # NAME -@@ -59,6 +60,8 @@ without any interruptions. - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - ~~~c - static int trailer_cb(struct curl_slist **tr, void *data) -@@ -77,7 +80,7 @@ int main(void) - /* Set the URL of the request */ - curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); - /* Now set it as a put */ -- curl_easy_setopt(curl, CURLOPT_PUT, 1L); -+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); - - /* Assuming we have a function that returns the data to be pushed - Let that function be read_cb */ -@@ -99,9 +102,8 @@ int main(void) - } - } - ~~~ --# AVAILABILITY - --This option was added in curl 7.64.0 and is present if HTTP support is enabled. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md b/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md -index 9506c96ed..d77274f7d 100644 ---- a/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md -+++ b/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_CRLF (3) - Protocol: - - All -+Added-in: 7.1.1 - --- - - # NAME -@@ -25,7 +26,7 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TRANSFERTEXT, long text); - # DESCRIPTION - - A parameter set to 1 tells the library to use ASCII mode for FTP transfers, --instead of the default binary transfer. For win32 systems it does not set the -+instead of the default binary transfer. For Win32 systems it does not set the - stdout to binary mode. This option can be usable when transferring text data - between systems with different views on certain characters, such as newlines - or similar. -@@ -38,6 +39,8 @@ simply sets the mode to ASCII and performs a standard transfer. - - 0, disabled - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -54,9 +57,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with FTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md -index 6494d45d4..a66784560 100644 ---- a/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md -+++ b/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_HTTP_TRANSFER_DECODING (3) - Protocol: - - HTTP -+Added-in: 7.21.6 - --- - - # NAME -@@ -43,6 +44,8 @@ by both HTTP clients and HTTP servers. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -57,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.6 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md -index fff993753..7b369f190 100644 ---- a/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md -+++ b/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md -@@ -10,6 +10,7 @@ See-also: - - unix (7) - Protocol: - - All -+Added-in: 7.40.0 - --- - - # NAME -@@ -37,17 +38,22 @@ does not resolve the DNS hostname in the URL. - The maximum path length on Cygwin, Linux and Solaris is 107. On other platforms - it might be even less. - --Proxy and TCP options such as CURLOPT_TCP_NODELAY(3) are not --supported. Proxy options such as CURLOPT_PROXY(3) have no effect either --as these are TCP-oriented, and asking a proxy server to connect to a certain --Unix domain socket is not possible. -+Proxy and TCP options such as CURLOPT_TCP_NODELAY(3) are not supported. Proxy -+options such as CURLOPT_PROXY(3) have no effect either as these are -+TCP-oriented, and asking a proxy server to connect to a certain Unix domain -+socket is not possible. - - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --Default is NULL, meaning that no Unix domain sockets are used. -+NULL - no Unix domain sockets are used. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -75,9 +81,7 @@ you can use the proc filesystem to bypass the limitation: - /* Be sure to keep dirfd valid until you discard the handle */ - ~~~ - --# AVAILABILITY -- --Added in 7.40.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md b/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md -index 270ebd654..a80c4f6f2 100644 ---- a/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md -+++ b/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md -@@ -12,6 +12,7 @@ See-also: - - CURLOPT_USERPWD (3) - Protocol: - - HTTP -+Added-in: 7.10.4 - --- - - # NAME -@@ -30,17 +31,19 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UNRESTRICTED_AUTH, - # DESCRIPTION - - Set the long *gohead* parameter to 1L to make libcurl continue to send --authentication (user+password) credentials when following locations, even when --hostname changed. This option is meaningful only when setting --CURLOPT_FOLLOWLOCATION(3). -+authentication (user+password) credentials or explicitly set cookie headers -+when following locations, even when the host changes. This option is -+meaningful only when setting CURLOPT_FOLLOWLOCATION(3). - --Further, when this option is not used or set to **0L**, libcurl does not --send custom nor internally generated Authentication: headers on requests done --to other hosts than the one used for the initial URL. -+Further, when this option is not used or set to **0L**, libcurl does not send -+custom nor internally generated `Authentication:` or `Cookie:` headers on -+requests done to other hosts than the one used for the initial URL. Another -+host means that one or more of hostname, protocol scheme or port number -+changed. - --By default, libcurl only sends credentials and Authentication headers to the --initial hostname as given in the original URL, to avoid leaking username + --password to other sites. -+By default, libcurl only sends `Authentication:` or explicitly set `Cookie:` -+headers to the initial host as given in the original URL, to avoid leaking -+username + password to other sites. - - This option should be used with caution: when curl follows redirects it - blindly fetches the next URL as instructed by the server. Setting -@@ -48,10 +51,17 @@ CURLOPT_UNRESTRICTED_AUTH(3) to 1L makes curl trust the server and sends - possibly sensitive credentials to any host the server points to, possibly - again and again as the following hosts can keep redirecting to new hosts. - -+Due to the way HTTP works, almost any header can be made to contain data a -+client may not want to pass on to other servers than the initially intended -+host and for all other headers than the two mentioned above, there is no -+protection from this happening when libcurl is told to follow redirects. -+ - # DEFAULT - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -67,9 +77,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Along with HTTP -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md b/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md -index 4813904d3..d8cdb90e3 100644 ---- a/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md -+++ b/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md -@@ -8,6 +8,7 @@ See-also: - - CURLOPT_TCP_KEEPALIVE (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -41,6 +42,8 @@ is called, an HTTP/2 PING frame is sent on the connection. - - CURL_UPKEEP_INTERVAL_DEFAULT (currently defined as 60000L, which is 60 seconds) - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_UPLOAD.md b/docs/libcurl/opts/CURLOPT_UPLOAD.md -index de64ada85..eec090662 100644 ---- a/docs/libcurl/opts/CURLOPT_UPLOAD.md -+++ b/docs/libcurl/opts/CURLOPT_UPLOAD.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_READFUNCTION (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -27,23 +28,25 @@ CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD, long upload); - # DESCRIPTION - - The long parameter *upload* set to 1 tells the library to prepare for and --perform an upload. The CURLOPT_READDATA(3) and --CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3) options are --also interesting for uploads. If the protocol is HTTP, uploading means using --the PUT request unless you tell libcurl otherwise. -+perform an upload. The CURLOPT_READDATA(3) and CURLOPT_INFILESIZE(3) or -+CURLOPT_INFILESIZE_LARGE(3) options are also interesting for uploads. If the -+protocol is HTTP, uploading means using the PUT request unless you tell -+libcurl otherwise. - - Using PUT with HTTP 1.1 implies the use of a "Expect: 100-continue" header. - You can disable this header with CURLOPT_HTTPHEADER(3) as usual. - - If you use PUT to an HTTP 1.1 server, you can upload data without knowing the - size before starting the transfer. The library enables this by adding a header --"Transfer-Encoding: chunked". With HTTP 1.0 or if you prefer not to use chunked --transfer, you must specify the size of the data with -+"Transfer-Encoding: chunked". With HTTP 1.0 or if you prefer not to use -+chunked transfer, you must specify the size of the data with - CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3). - - # DEFAULT - --0, default is download -+0 -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -80,15 +83,13 @@ int main(void) - /* Set the size of the file to upload */ - curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); - -- /* Now run off and do what you have been told! */ -+ /* Now run off and do what you have been told */ - curl_easy_perform(curl); - } - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md b/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md -index e1cbf244a..72a4b64d5 100644 ---- a/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md -+++ b/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_TCP_NODELAY (3) - Protocol: - - All -+Added-in: 7.62.0 - --- - - # NAME -@@ -49,6 +50,8 @@ transfer as that may lead to unintended consequences. - - 65536 bytes - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.62.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_URL.md b/docs/libcurl/opts/CURLOPT_URL.md -index 2522d96ba..93dacdf27 100644 ---- a/docs/libcurl/opts/CURLOPT_URL.md -+++ b/docs/libcurl/opts/CURLOPT_URL.md -@@ -10,12 +10,13 @@ See-also: - - CURLOPT_FORBID_REUSE (3) - - CURLOPT_FRESH_CONNECT (3) - - CURLOPT_PATH_AS_IS (3) -- - CURLOPT_PROTOCOLS (3) -+ - CURLOPT_PROTOCOLS_STR (3) - - curl_easy_perform (3) - - curl_url_get (3) - - curl_url_set (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -70,6 +71,10 @@ transfer is started. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. Note however that -+libcurl needs a URL set to be able to performed a transfer. -+ - The parser used for handling the URL set with CURLOPT_URL(3) is the same - that curl_url_set(3) uses. - -@@ -80,15 +85,14 @@ expected to be a sequence of characters using an ASCII compatible encoding. - - If libcurl is built with IDN support, the server name part of the URL can use - an "international name" by using the current encoding (according to locale) or --UTF-8 (when winidn is used; or a Windows Unicode build using libidn2). -+UTF-8 (when WinIDN is used; or a Windows Unicode build using libidn2). - - If libcurl is built without IDN support, the server name is used exactly as - specified when passed to the name resolver functions. - - # DEFAULT - --There is no default URL. If this option is not set, no transfer can be --performed. -+NULL. If this option is not set, no transfer can be performed. - - # SECURITY CONCERNS - -@@ -109,11 +113,13 @@ custom port number can allow external users to play tricks with your local - services. - - Accepting external URLs may also use other protocols than http:// or other --common ones. Restrict what accept with CURLOPT_PROTOCOLS(3). -+common ones. Restrict what accept with CURLOPT_PROTOCOLS_STR(3). - - User provided URLs can also be made to point to sites that redirect further on - (possibly to other protocols too). Consider your --CURLOPT_FOLLOWLOCATION(3) and CURLOPT_REDIR_PROTOCOLS(3) settings. -+CURLOPT_FOLLOWLOCATION(3) and CURLOPT_REDIR_PROTOCOLS_STR(3) settings. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -129,9 +135,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --POP3 and SMTP were added in 7.31.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_USERAGENT.md b/docs/libcurl/opts/CURLOPT_USERAGENT.md -index 757f3edbd..e10ff0cff 100644 ---- a/docs/libcurl/opts/CURLOPT_USERAGENT.md -+++ b/docs/libcurl/opts/CURLOPT_USERAGENT.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_REQUEST_TARGET (3) - Protocol: - - HTTP -+Added-in: 7.1 - --- - - # NAME -@@ -34,9 +35,14 @@ can also set any custom header with CURLOPT_HTTPHEADER(3). - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - --NULL, no User-Agent: header is used by default. -+NULL, no User-Agent: header is used. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -54,9 +60,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --As long as HTTP is supported -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_USERNAME.md b/docs/libcurl/opts/CURLOPT_USERNAME.md -index 34d0a6793..727421946 100644 ---- a/docs/libcurl/opts/CURLOPT_USERNAME.md -+++ b/docs/libcurl/opts/CURLOPT_USERNAME.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_USERPWD (3) - Protocol: - - All -+Added-in: 7.19.1 - --- - - # NAME -@@ -60,6 +61,8 @@ option. - - blank - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -79,9 +82,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.19.1 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_USERPWD.md b/docs/libcurl/opts/CURLOPT_USERPWD.md -index 726ec3e72..b9db9faf6 100644 ---- a/docs/libcurl/opts/CURLOPT_USERPWD.md -+++ b/docs/libcurl/opts/CURLOPT_USERPWD.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_USERNAME (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -62,10 +63,15 @@ for that, or include it in the URL. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -85,9 +91,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_USE_SSL.md b/docs/libcurl/opts/CURLOPT_USE_SSL.md -index acb99e080..c74be586b 100644 ---- a/docs/libcurl/opts/CURLOPT_USE_SSL.md -+++ b/docs/libcurl/opts/CURLOPT_USE_SSL.md -@@ -13,6 +13,7 @@ Protocol: - - SMTP - - POP3 - - IMAP -+Added-in: 7.17.0 - --- - - # NAME -@@ -58,6 +59,8 @@ Require SSL for all communication or fail with *CURLE_USE_SSL_FAILED*. - - CURLUSESSL_NONE - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -76,11 +79,13 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+This option was known as CURLOPT_FTP_SSL up to 7.16.4, and the constants were -+known as CURLFTPSSL_* Handled by LDAP since 7.81.0. Fully supported by the -+OpenLDAP backend only. - --Added in 7.11.0. This option was known as CURLOPT_FTP_SSL up to 7.16.4, and --the constants were known as CURLFTPSSL_* --Handled by LDAP since 7.81.0. Fully supported by the OpenLDAP backend only. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_VERBOSE.md b/docs/libcurl/opts/CURLOPT_VERBOSE.md -index a144d29f9..b242fcbc4 100644 ---- a/docs/libcurl/opts/CURLOPT_VERBOSE.md -+++ b/docs/libcurl/opts/CURLOPT_VERBOSE.md -@@ -11,6 +11,7 @@ See-also: - - curl_global_trace (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -42,6 +43,8 @@ CURLOPT_DEBUGFUNCTION(3). - - 0, meaning disabled. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -60,9 +63,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Always -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md b/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md -index bfcc82fc7..e6ca3d655 100644 ---- a/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md -+++ b/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md -@@ -11,6 +11,7 @@ See-also: - - CURLOPT_URL (3) - Protocol: - - FTP -+Added-in: 7.21.0 - --- - - # NAME -@@ -76,6 +77,8 @@ Using the rules above, a filename pattern can be constructed: - - ftp://example.com/some/path/[a-z[:upper:]\\].jpg - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -100,9 +103,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.21.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_WRITEDATA.md b/docs/libcurl/opts/CURLOPT_WRITEDATA.md -index 66744abbe..c042a19e0 100644 ---- a/docs/libcurl/opts/CURLOPT_WRITEDATA.md -+++ b/docs/libcurl/opts/CURLOPT_WRITEDATA.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_WRITEFUNCTION (3) - Protocol: - - All -+Added-in: 7.9.7 - --- - - # NAME -@@ -41,20 +42,24 @@ crashes. - - # DEFAULT - --By default, this is a FILE * to stdout. -+stdout -+ -+# %PROTOCOLS% - - # EXAMPLE - - A common technique is to use the write callback to store the incoming data - into a dynamically growing allocated buffer, and then this --CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store --data in. Like in the getinmemory example: -+CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store data -+in. Like in the getinmemory example: - https://curl.se/libcurl/c/getinmemory.html - --# AVAILABILITY -+# HISTORY -+ -+This option was formerly known as CURLOPT_FILE, the name CURLOPT_WRITEDATA(3) -+was added in 7.9.7. - --Available in all libcurl versions. This option was formerly known as --CURLOPT_FILE, the name CURLOPT_WRITEDATA(3) was added in 7.9.7. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md -index 61a02c4c5..3ee11d8e4 100644 ---- a/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_WRITEDATA (3) - Protocol: - - All -+Added-in: 7.1 - --- - - # NAME -@@ -72,7 +73,9 @@ do that. - - # DEFAULT - --libcurl uses 'fwrite' as a callback by default. -+fwrite(3) -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -85,14 +88,14 @@ struct memory { - size_t size; - }; - --static size_t cb(void *data, size_t size, size_t nmemb, void *clientp) -+static size_t cb(char *data, size_t size, size_t nmemb, void *clientp) - { - size_t realsize = size * nmemb; - struct memory *mem = (struct memory *)clientp; - - char *ptr = realloc(mem->response, mem->size + realsize + 1); - if(!ptr) -- return 0; /* out of memory! */ -+ return 0; /* out of memory */ - - mem->response = ptr; - memcpy(&(mem->response[mem->size]), data, realsize); -@@ -125,10 +128,12 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY - - Support for the CURL_WRITEFUNC_PAUSE return code was added in version 7.18.0. - -+# %AVAILABILITY% -+ - # RETURN VALUE - - This returns CURLE_OK. -diff --git a/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md b/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md -index 23db0a47b..3eba3705f 100644 ---- a/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md -+++ b/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md -@@ -10,6 +10,7 @@ See-also: - - curl_ws_send (3) - Protocol: - - WS -+Added-in: 7.86.0 - --- - - # NAME -@@ -47,6 +48,8 @@ application. - - 0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.86.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_XFERINFODATA.md b/docs/libcurl/opts/CURLOPT_XFERINFODATA.md -index 126dc11a4..4ed174eff 100644 ---- a/docs/libcurl/opts/CURLOPT_XFERINFODATA.md -+++ b/docs/libcurl/opts/CURLOPT_XFERINFODATA.md -@@ -10,6 +10,7 @@ See-also: - - CURLOPT_XFERINFOFUNCTION (3) - Protocol: - - All -+Added-in: 7.32.0 - --- - - # NAME -@@ -33,7 +34,9 @@ This is an alias for CURLOPT_PROGRESSDATA(3). - - # DEFAULT - --The default value of this parameter is NULL. -+NULL -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -69,9 +72,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.32.0 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md b/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md -index 7fcd0e06d..e2f95371a 100644 ---- a/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md -+++ b/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md -@@ -9,6 +9,7 @@ See-also: - - CURLOPT_XFERINFODATA (3) - Protocol: - - All -+Added-in: 7.32.0 - --- - - # NAME -@@ -55,12 +56,14 @@ you only download data, the upload size remains 0). Many times the callback is - called one or more times first, before it knows the data sizes so a program - must be made to handle that. - -+Return zero from the callback if everything is fine. -+ -+Return 1 from this callback to make libcurl abort the transfer and return -+*CURLE_ABORTED_BY_CALLBACK*. -+ - If your callback function returns CURL_PROGRESSFUNC_CONTINUE it makes libcurl - to continue executing the default progress function. - --Returning any other non-zero value from this callback makes libcurl abort the --transfer and return *CURLE_ABORTED_BY_CALLBACK*. -- - If you transfer data with the multi interface, this function is not called - during periods of idleness unless you call the appropriate libcurl function - that performs transfers. -@@ -70,8 +73,9 @@ get called. - - # DEFAULT - --By default, libcurl has an internal progress meter. That is rarely wanted by --users. -+NULL - use the internal progress meter. That is rarely wanted by users. -+ -+# %PROTOCOLS% - - # EXAMPLE - -@@ -104,14 +108,15 @@ int main(void) - /* pass struct to callback */ - curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data); - -+ /* enable progress callback getting called */ -+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); -+ - curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); - } - } - ~~~ - --# AVAILABILITY -- --Added in 7.32.0. This callback replaces CURLOPT_PROGRESSFUNCTION(3) -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md -index 8ae9901d6..742896583 100644 ---- a/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md -+++ b/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md -@@ -13,6 +13,7 @@ Protocol: - - LDAP - - POP3 - - SMTP -+Added-in: 7.33.0 - --- - - # NAME -@@ -39,10 +40,15 @@ Token should be supplied via the CURLOPT_USERNAME(3) option. - The application does not have to keep the string around after setting this - option. - -+Using this option multiple times makes the last set string override the -+previous ones. Set it to NULL to disable its use again. -+ - # DEFAULT - - NULL - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +65,11 @@ int main(void) - } - ~~~ - --# AVAILABILITY -+# HISTORY -+ -+Support for OpenLDAP added in 7.82.0. - --Added in 7.33.0. Support for OpenLDAP added in 7.82.0. -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md b/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md -index 46e210ad5..208dfdd62 100644 ---- a/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md -+++ b/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md -@@ -11,6 +11,7 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -48,6 +49,8 @@ sure that the callback uses a different lock for each kind of data. - *clientp* is the private pointer you set with CURLSHOPT_USERDATA(3). - This pointer is not used by libcurl itself. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -64,9 +67,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLSHOPT_SHARE.md b/docs/libcurl/opts/CURLSHOPT_SHARE.md -index 376d53cda..fa6838cb8 100644 ---- a/docs/libcurl/opts/CURLSHOPT_SHARE.md -+++ b/docs/libcurl/opts/CURLSHOPT_SHARE.md -@@ -11,6 +11,7 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -40,6 +41,8 @@ Cookie data is shared across the easy handles using this shared object. Note - that this does not activate an easy handle's cookie handling. You can do that - separately by using CURLOPT_COOKIEFILE(3) for example. - -+It is not supported to share cookies between multiple concurrent threads. -+ - ## CURL_LOCK_DATA_DNS - - Cached DNS hosts are shared across the easy handles using this shared -@@ -54,6 +57,8 @@ the same server. Note SSL session IDs are reused within the same easy handle - by default. Note this symbol was added in 7.10.3 but was not implemented until - 7.23.0. - -+It is not supported to share SSL sessions between multiple concurrent threads. -+ - ## CURL_LOCK_DATA_CONNECT - - Put the connection cache in the share object and make all easy handles using -@@ -61,9 +66,9 @@ this share object share the connection cache. - - It is not supported to share connections between multiple concurrent threads. - --Connections that are used for HTTP/1.1 Pipelining or HTTP/2 multiplexing only --get additional transfers added to them if the existing connection is held by --the same multi or easy handle. libcurl does not support doing HTTP/2 streams -+Connections that are used for HTTP/2 or HTTP/3 multiplexing only get -+additional transfers added to them if the existing connection is held by the -+same multi or easy handle. libcurl does not support doing multiplexed streams - in different threads using a shared connection. - - Support for **CURL_LOCK_DATA_CONNECT** was added in 7.57.0, but the symbol -@@ -91,6 +96,8 @@ It is not supported to share the HSTS between multiple concurrent threads. - - Added in 7.88.0 - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -104,9 +111,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md b/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md -index ae8ecb779..503918231 100644 ---- a/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md -+++ b/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md -@@ -11,6 +11,7 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -44,6 +45,8 @@ sure that the callback uses a different lock for each kind of data. - *clientp* is the private pointer you set with CURLSHOPT_USERDATA(3). - This pointer is not used by libcurl itself. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -59,9 +62,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLSHOPT_UNSHARE.md b/docs/libcurl/opts/CURLSHOPT_UNSHARE.md -index 69ee517c7..43edb4d25 100644 ---- a/docs/libcurl/opts/CURLSHOPT_UNSHARE.md -+++ b/docs/libcurl/opts/CURLSHOPT_UNSHARE.md -@@ -11,6 +11,7 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -58,6 +59,8 @@ The connection cache is no longer shared. - - The Public Suffix List is no longer shared. - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -71,9 +74,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/CURLSHOPT_USERDATA.md b/docs/libcurl/opts/CURLSHOPT_USERDATA.md -index 9cd042ec5..5796ce21b 100644 ---- a/docs/libcurl/opts/CURLSHOPT_USERDATA.md -+++ b/docs/libcurl/opts/CURLSHOPT_USERDATA.md -@@ -11,6 +11,7 @@ See-also: - - curl_share_setopt (3) - Protocol: - - All -+Added-in: 7.10.3 - --- - - # NAME -@@ -31,6 +32,8 @@ The *clientp* parameter is held verbatim by libcurl and is passed on as - the *clientp* argument to the callbacks set with - CURLSHOPT_LOCKFUNC(3) and CURLSHOPT_UNLOCKFUNC(3). - -+# %PROTOCOLS% -+ - # EXAMPLE - - ~~~c -@@ -49,9 +52,7 @@ int main(void) - } - ~~~ - --# AVAILABILITY -- --Added in 7.10 -+# %AVAILABILITY% - - # RETURN VALUE - -diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc -index 7a292b81d..8591f47b5 100644 ---- a/docs/libcurl/opts/Makefile.inc -+++ b/docs/libcurl/opts/Makefile.inc -@@ -32,14 +32,15 @@ man_MANS = \ - CURLINFO_CERTINFO.3 \ - CURLINFO_CONDITION_UNMET.3 \ - CURLINFO_CONNECT_TIME.3 \ -- CURLINFO_CONNECT_TIME_T.3 \ - CURLINFO_CONN_ID.3 \ -+ CURLINFO_CONNECT_TIME_T.3 \ - CURLINFO_CONTENT_LENGTH_DOWNLOAD.3 \ - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.3 \ - CURLINFO_CONTENT_LENGTH_UPLOAD.3 \ - CURLINFO_CONTENT_LENGTH_UPLOAD_T.3 \ - CURLINFO_CONTENT_TYPE.3 \ - CURLINFO_COOKIELIST.3 \ -+ CURLINFO_EARLYDATA_SENT_T.3 \ - CURLINFO_EFFECTIVE_METHOD.3 \ - CURLINFO_EFFECTIVE_URL.3 \ - CURLINFO_FILETIME.3 \ -@@ -58,6 +59,7 @@ man_MANS = \ - CURLINFO_OS_ERRNO.3 \ - CURLINFO_PRETRANSFER_TIME.3 \ - CURLINFO_PRETRANSFER_TIME_T.3 \ -+ CURLINFO_POSTTRANSFER_TIME_T.3 \ - CURLINFO_PRIMARY_IP.3 \ - CURLINFO_PRIMARY_PORT.3 \ - CURLINFO_PRIVATE.3 \ -@@ -166,6 +168,7 @@ man_MANS = \ - CURLOPT_DOH_SSL_VERIFYPEER.3 \ - CURLOPT_DOH_SSL_VERIFYSTATUS.3 \ - CURLOPT_DOH_URL.3 \ -+ CURLOPT_ECH.3 \ - CURLOPT_EGDSOCKET.3 \ - CURLOPT_ERRORBUFFER.3 \ - CURLOPT_EXPECT_100_TIMEOUT_MS.3 \ -@@ -383,6 +386,7 @@ man_MANS = \ - CURLOPT_TCP_KEEPALIVE.3 \ - CURLOPT_TCP_KEEPIDLE.3 \ - CURLOPT_TCP_KEEPINTVL.3 \ -+ CURLOPT_TCP_KEEPCNT.3 \ - CURLOPT_TCP_NODELAY.3 \ - CURLOPT_TELNETOPTIONS.3 \ - CURLOPT_TFTP_BLKSIZE.3 \ -diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions -index a627dd68b..ddda26d83 100644 ---- a/docs/libcurl/symbols-in-versions -+++ b/docs/libcurl/symbols-in-versions -@@ -177,7 +177,7 @@ CURL_VERSION_LARGEFILE 7.11.1 - CURL_VERSION_LIBZ 7.10 - CURL_VERSION_MULTI_SSL 7.56.0 - CURL_VERSION_NTLM 7.10.6 --CURL_VERSION_NTLM_WB 7.22.0 -+CURL_VERSION_NTLM_WB 7.22.0 8.8.0 - CURL_VERSION_PSL 7.47.0 - CURL_VERSION_SPNEGO 7.10.8 - CURL_VERSION_SSL 7.10 -@@ -210,7 +210,7 @@ CURLAUTH_GSSNEGOTIATE 7.10.6 7.38.0 - CURLAUTH_NEGOTIATE 7.38.0 - CURLAUTH_NONE 7.10.6 - CURLAUTH_NTLM 7.10.6 --CURLAUTH_NTLM_WB 7.22.0 -+CURLAUTH_NTLM_WB 7.22.0 8.8.0 - CURLAUTH_ONLY 7.21.3 - CURLCLOSEPOLICY_CALLBACK 7.7 7.16.1 - CURLCLOSEPOLICY_LEAST_RECENTLY_USED 7.7 7.16.1 -@@ -340,6 +340,7 @@ CURLE_URL_MALFORMAT_USER 7.1 7.17.0 - CURLE_USE_SSL_FAILED 7.17.0 - CURLE_WEIRD_SERVER_REPLY 7.51.0 - CURLE_WRITE_ERROR 7.1 -+CURLE_ECH_REQUIRED 8.8.0 - CURLFILETYPE_DEVICE_BLOCK 7.21.0 - CURLFILETYPE_DEVICE_CHAR 7.21.0 - CURLFILETYPE_DIRECTORY 7.21.0 -@@ -434,6 +435,7 @@ CURLINFO_COOKIELIST 7.14.1 - CURLINFO_DATA_IN 7.9.6 - CURLINFO_DATA_OUT 7.9.6 - CURLINFO_DOUBLE 7.4.1 -+CURLINFO_EARLYDATA_SENT_T 8.11.0 - CURLINFO_EFFECTIVE_METHOD 7.72.0 - CURLINFO_EFFECTIVE_URL 7.4 - CURLINFO_END 7.9.6 -@@ -461,6 +463,7 @@ CURLINFO_OFF_T 7.55.0 - CURLINFO_OS_ERRNO 7.12.2 - CURLINFO_PRETRANSFER_TIME 7.4.1 - CURLINFO_PRETRANSFER_TIME_T 7.61.0 -+CURLINFO_POSTTRANSFER_TIME_T 8.10.0 - CURLINFO_PRIMARY_IP 7.19.0 - CURLINFO_PRIMARY_PORT 7.21.0 - CURLINFO_PRIVATE 7.10.3 -@@ -617,6 +620,7 @@ CURLOPT_DOH_SSL_VERIFYHOST 7.76.0 - CURLOPT_DOH_SSL_VERIFYPEER 7.76.0 - CURLOPT_DOH_SSL_VERIFYSTATUS 7.76.0 - CURLOPT_DOH_URL 7.62.0 -+CURLOPT_ECH 8.8.0 - CURLOPT_EGDSOCKET 7.7 7.84.0 - CURLOPT_ENCODING 7.10 7.21.6 - CURLOPT_ERRORBUFFER 7.1 -@@ -862,6 +866,7 @@ CURLOPT_TCP_FASTOPEN 7.49.0 - CURLOPT_TCP_KEEPALIVE 7.25.0 - CURLOPT_TCP_KEEPIDLE 7.25.0 - CURLOPT_TCP_KEEPINTVL 7.25.0 -+CURLOPT_TCP_KEEPCNT 8.9.0 - CURLOPT_TCP_NODELAY 7.11.2 - CURLOPT_TELNETOPTIONS 7.7 - CURLOPT_TFTP_BLKSIZE 7.19.4 -@@ -1050,6 +1055,7 @@ CURLSSLOPT_NATIVE_CA 7.71.0 - CURLSSLOPT_NO_PARTIALCHAIN 7.68.0 - CURLSSLOPT_NO_REVOKE 7.44.0 - CURLSSLOPT_REVOKE_BEST_EFFORT 7.70.0 -+CURLSSLOPT_EARLYDATA 8.11.0 - CURLSSLSET_NO_BACKENDS 7.56.0 - CURLSSLSET_OK 7.56.0 - CURLSSLSET_TOO_LATE 7.56.0 -@@ -1062,9 +1068,11 @@ CURLU_APPENDQUERY 7.62.0 - CURLU_DEFAULT_PORT 7.62.0 - CURLU_DEFAULT_SCHEME 7.62.0 - CURLU_DISALLOW_USER 7.62.0 -+CURLU_GET_EMPTY 8.8.0 - CURLU_GUESS_SCHEME 7.62.0 - CURLU_NO_AUTHORITY 7.67.0 - CURLU_NO_DEFAULT_PORT 7.62.0 -+CURLU_NO_GUESS_SCHEME 8.9.0 - CURLU_NON_SUPPORT_SCHEME 7.62.0 - CURLU_PATH_AS_IS 7.62.0 - CURLU_PUNY2IDN 8.3.0 -@@ -1130,6 +1138,7 @@ CURLVERSION_SEVENTH 7.70.0 - CURLVERSION_SIXTH 7.66.0 - CURLVERSION_TENTH 7.77.0 - CURLVERSION_THIRD 7.12.0 -+CURLVERSION_TWELFTH 8.8.0 - CURLWARNING 7.66.0 - CURLWS_BINARY 7.86.0 - CURLWS_CLOSE 7.86.0 -diff --git a/docs/mk-ca-bundle.md b/docs/mk-ca-bundle.md -index 8a8130998..fe6863526 100644 ---- a/docs/mk-ca-bundle.md -+++ b/docs/mk-ca-bundle.md -@@ -6,6 +6,7 @@ Section: 1 - Source: mk-ca-bundle - See-also: - - curl (1) -+Added-in: n/a - --- - - # NAME -diff --git a/docs/options-in-versions b/docs/options-in-versions -index 090580943..a7a11630d 100644 ---- a/docs/options-in-versions -+++ b/docs/options-in-versions -@@ -54,7 +54,9 @@ - --doh-cert-status 7.76.0 - --doh-insecure 7.76.0 - --doh-url 7.62.0 -+--dump-ca-embed 8.10.0 - --dump-header (-D) 5.7 -+--ech 8.8.0 - --egd-file 7.7 - --engine 7.9.3 - --etag-compare 7.68.0 -@@ -97,14 +99,15 @@ - --http3 7.66.0 - --http3-only 7.88.0 - --ignore-content-length 7.14.1 -+--ip-tos 8.9.0 - --ipfs-gateway 8.4.0 ----include (-i) 4.8 - --insecure (-k) 7.10 - --interface 7.3 - --ipv4 (-4) 7.10.8 - --ipv6 (-6) 7.10.8 - --json 7.82.0 - --junk-session-cookies (-j) 7.9.7 -+--keepalive-cnt 8.9.0 - --keepalive-time 7.18.0 - --key 7.9.3 - --key-type 7.9.3 -@@ -125,6 +128,7 @@ - --max-redirs 7.5 - --max-time (-m) 4.0 - --metalink 7.27.0 -+--mptcp 8.9.0 - --negotiate 7.10.6 - --netrc (-n) 4.6 - --netrc-file 7.21.5 -@@ -212,7 +216,9 @@ - --sasl-ir 7.31.0 - --service-name 7.43.0 - --show-error (-S) 5.9 -+--show-headers (-i) 4.8 - --silent (-s) 4.0 -+--skip-existing 8.10.0 - --socks4 7.15.2 - --socks4a 7.18.0 - --socks5 7.18.0 -@@ -240,6 +246,7 @@ - --tftp-blksize 7.20.0 - --tftp-no-options 7.48.0 - --time-cond (-z) 5.8 -+--tls-earlydata 8.11.0 - --tls-max 7.54.0 - --tls13-ciphers 7.61.0 - --tlsauthtype 7.21.4 -@@ -266,5 +273,6 @@ - --variable 8.3.0 - --verbose (-v) 4.0 - --version (-V) 4.0 -+--vlan-priority 8.9.0 - --write-out (-w) 6.5 - --xattr 7.21.3 -diff --git a/export.sh b/export.sh -new file mode 100755 -index 000000000..7bced6879 ---- /dev/null -+++ b/export.sh -@@ -0,0 +1,9 @@ -+#!/bin/bash -+ -+# TODO: use cmake to generate mingw makefile, see: -+# -+# 1. https://github.com/curl/curl/pull/13244/files -+# 2. https://everything.curl.dev/build/windows.html -+ -+git df curl-8_7_1 > chrome.patch -+mv chrome.patch ../curl-impersonate/chrome/patches/curl-impersonate.patch -diff --git a/include/curl/curl.h b/include/curl/curl.h -index b2377b789..d695b803e 100644 ---- a/include/curl/curl.h -+++ b/include/curl/curl.h -@@ -632,6 +632,7 @@ typedef enum { - CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */ - CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ - CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ -+ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */ - CURL_LAST /* never use! */ - } CURLcode; - -@@ -2206,6 +2207,85 @@ typedef enum { - /* millisecond version */ - CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), - -+ /* curl-impersonate: A list of headers used by the impersonated browser. -+ * If given, merged with CURLOPT_HTTPHEADER. */ -+ CURLOPT(CURLOPT_HTTPBASEHEADER, CURLOPTTYPE_SLISTPOINT, 1000), -+ -+ /* curl-impersonate: A list of TLS signature hash algorithms. -+ * See https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1 */ -+ CURLOPT(CURLOPT_SSL_SIG_HASH_ALGS, CURLOPTTYPE_STRINGPOINT, 1001), -+ -+ /* curl-impersonate: Whether to enable ALPS in TLS or not. -+ * See https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps. -+ * Support for ALPS is minimal and is intended only for the TLS client -+ * hello to match. */ -+ CURLOPT(CURLOPT_SSL_ENABLE_ALPS, CURLOPTTYPE_LONG, 1002), -+ -+ /* curl-impersonate: Comma-separated list of certificate compression -+ * algorithms to use. These are published in the client hello. -+ * Supported algorithms are "zlib" and "brotli". -+ * See https://datatracker.ietf.org/doc/html/rfc8879 */ -+ CURLOPT(CURLOPT_SSL_CERT_COMPRESSION, CURLOPTTYPE_STRINGPOINT, 1003), -+ -+ /* Enable/disable TLS session ticket extension (RFC5077) */ -+ CURLOPT(CURLOPT_SSL_ENABLE_TICKET, CURLOPTTYPE_LONG, 1004), -+ -+ /* -+ * curl-impersonate: -+ * Set the order of the HTTP/2 pseudo headers. The value must contain -+ * the letters 'm', 'a', 's', 'p' representing the pseudo-headers -+ * ":method", ":authority", ":scheme", ":path" in the desired order of -+ * appearance in the HTTP/2 HEADERS frame. -+ */ -+ CURLOPT(CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, CURLOPTTYPE_STRINGPOINT, 1005), -+ -+ /* -+ * curl-impersonate: -+ * HTTP2 settings frame keys and values, format: 1:v;2:v;3:v -+ */ -+ CURLOPT(CURLOPT_HTTP2_SETTINGS, CURLOPTTYPE_STRINGPOINT, 1006), -+ -+ /* -+ * curl-impersonate: Whether to enable Boringssl permute extensions -+ * See https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_permute_extensions. -+ */ -+ CURLOPT(CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOPTTYPE_LONG, 1007), -+ -+ /* -+ * curl-impersonate: -+ * HTTP2 initial window update -+ */ -+ CURLOPT(CURLOPT_HTTP2_WINDOW_UPDATE, CURLOPTTYPE_LONG, 1008), -+ -+ /* curl-impersonate: -+ * set ECH configuration -+ */ -+ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 1009), -+ -+ /* -+ * curl-impersonate: -+ * Set the initial streams settings for http2. -+ */ -+ CURLOPT(CURLOPT_HTTP2_STREAMS, CURLOPTTYPE_STRINGPOINT, 1010), -+ -+ /* curl-impersonate: enable tls grease */ -+ CURLOPT(CURLOPT_TLS_GREASE, CURLOPTTYPE_LONG, 1011), -+ -+ /* curl-impersonate: set tls extension order */ -+ CURLOPT(CURLOPT_TLS_EXTENSION_ORDER, CURLOPTTYPE_STRINGPOINT, 1012), -+ -+ /* curl-impersonate: Set stream exclusiveness, 0 or 1 */ -+ CURLOPT(CURLOPT_STREAM_EXCLUSIVE, CURLOPTTYPE_LONG, 1013), -+ -+ /* curl-impersonate: enable tls key usage check, defaults: on */ -+ CURLOPT(CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOPTTYPE_LONG, 1014), -+ -+ /* curl-impersonate: enable tls signed cert stamps */ -+ CURLOPT(CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, CURLOPTTYPE_LONG, 1015), -+ -+ /* curl-impersonate: enable tls status request */ -+ CURLOPT(CURLOPT_TLS_STATUS_REQUEST, CURLOPTTYPE_LONG, 1016), -+ - CURLOPT_LASTENTRY /* the last unused */ - } CURLoption; - -diff --git a/include/curl/easy.h b/include/curl/easy.h -index 1285101c5..c620065dc 100644 ---- a/include/curl/easy.h -+++ b/include/curl/easy.h -@@ -43,6 +43,16 @@ CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); - CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); - CURL_EXTERN void curl_easy_cleanup(CURL *curl); - -+/* -+ * curl-impersonate: Tell libcurl to impersonate a browser. -+ * This is a wrapper function that calls curl_easy_setopt() -+ * multiple times with all the parameters required. That's also why it was -+ * created as a separate API function and not just as another option to -+ * curl_easy_setopt(). -+ */ -+CURL_EXTERN CURLcode curl_easy_impersonate(CURL *curl, const char *target, -+ int default_headers); -+ - /* - * NAME curl_easy_getinfo() - * -diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h -index b880f3dc6..79074e011 100644 ---- a/include/curl/typecheck-gcc.h -+++ b/include/curl/typecheck-gcc.h -@@ -275,6 +275,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, - (option) == CURLOPT_DNS_LOCAL_IP6 || \ - (option) == CURLOPT_DNS_SERVERS || \ - (option) == CURLOPT_DOH_URL || \ -+ (option) == CURLOPT_ECH || \ - (option) == CURLOPT_EGDSOCKET || \ - (option) == CURLOPT_FTP_ACCOUNT || \ - (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 1237c8e99..6b2961018 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -31,7 +31,7 @@ EXTRA_DIST = Makefile.mk config-win32.h config-win32ce.h config-plan9.h \ - config-os400.h setup-os400.h $(CMAKE_DIST) setup-win32.h .checksrc \ - Makefile.soname - --lib_LTLIBRARIES = libcurl.la -+lib_LTLIBRARIES = libcurl-impersonate-chrome.la - - if BUILD_UNITTESTS - noinst_LTLIBRARIES = libcurlu.la -@@ -67,51 +67,51 @@ AM_CFLAGS = - # Makefile.inc provides the CSOURCES and HHEADERS defines - include Makefile.inc - --libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) -+libcurl_impersonate_chrome_la_SOURCES = $(CSOURCES) $(HHEADERS) - libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS) - --libcurl_la_CPPFLAGS_EXTRA = --libcurl_la_LDFLAGS_EXTRA = --libcurl_la_CFLAGS_EXTRA = -+libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA = -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA = -+libcurl_impersonate_chrome_la_CFLAGS_EXTRA = - - if CURL_LT_SHLIB_USE_VERSION_INFO --libcurl_la_LDFLAGS_EXTRA += $(VERSIONINFO) -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += $(VERSIONINFO) - endif - - if CURL_LT_SHLIB_USE_NO_UNDEFINED --libcurl_la_LDFLAGS_EXTRA += -no-undefined -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -no-undefined - endif - - if CURL_LT_SHLIB_USE_MIMPURE_TEXT --libcurl_la_LDFLAGS_EXTRA += -mimpure-text -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -mimpure-text - endif - - if CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS --libcurl_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -Wl,--version-script=libcurl.vers - else - # if symbol-hiding is enabled, hide them! - if DOING_CURL_SYMBOL_HIDING --libcurl_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' -+libcurl_impersonate_chrome_la_LDFLAGS_EXTRA += -export-symbols-regex '^curl_.*' - endif - endif - - if USE_CPPFLAG_CURL_STATICLIB --libcurl_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB -+libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA += -DCURL_STATICLIB - else - if HAVE_WINDRES --libcurl_la_SOURCES += $(LIB_RCFILES) -+libcurl_impersonate_chrome_la_SOURCES += $(LIB_RCFILES) - $(LIB_RCFILES): $(top_srcdir)/include/curl/curlver.h - endif - endif - - if DOING_CURL_SYMBOL_HIDING --libcurl_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS --libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) -+libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS -+libcurl_impersonate_chrome_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) - endif - --libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) --libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) --libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) -+libcurl_impersonate_chrome_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_impersonate_chrome_la_CPPFLAGS_EXTRA) -+libcurl_impersonate_chrome_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_impersonate_chrome_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_LIBS) -+libcurl_impersonate_chrome_la_CFLAGS = $(AM_CFLAGS) $(libcurl_impersonate_chrome_la_CFLAGS_EXTRA) - - libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS - libcurlu_la_LDFLAGS = $(AM_LDFLAGS) -static $(LIBCURL_LIBS) -diff --git a/lib/Makefile.inc b/lib/Makefile.inc -index 400e2b1ac..ff3e479aa 100644 ---- a/lib/Makefile.inc -+++ b/lib/Makefile.inc -@@ -177,6 +177,7 @@ LIB_CFILES = \ - idn.c \ - if2ip.c \ - imap.c \ -+ impersonate.c \ - inet_ntop.c \ - inet_pton.c \ - krb5.c \ -diff --git a/lib/content_encoding.c b/lib/content_encoding.c -index c1abf24e8..8e926dd2e 100644 ---- a/lib/content_encoding.c -+++ b/lib/content_encoding.c -@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data, - struct zlib_writer *zp = (struct zlib_writer *) writer; - z_stream *z = &zp->z; /* zlib state structure */ - -- if(!(type & CLIENTWRITE_BODY)) -+ if(!(type & CLIENTWRITE_BODY) || !nbytes) - return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - - /* Set the compressed input when this function is called */ -@@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data, - struct zlib_writer *zp = (struct zlib_writer *) writer; - z_stream *z = &zp->z; /* zlib state structure */ - -- if(!(type & CLIENTWRITE_BODY)) -+ if(!(type & CLIENTWRITE_BODY) || !nbytes) - return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - - if(zp->zlib_init == ZLIB_INIT_GZIP) { -@@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data, - CURLcode result = CURLE_OK; - BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; - -- if(!(type & CLIENTWRITE_BODY)) -+ if(!(type & CLIENTWRITE_BODY) || !nbytes) - return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - - if(!bp->br) -@@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data, - ZSTD_outBuffer out; - size_t errorCode; - -- if(!(type & CLIENTWRITE_BODY)) -+ if(!(type & CLIENTWRITE_BODY) || !nbytes) - return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - - if(!zp->decomp) { -@@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data, - (void) buf; - (void) nbytes; - -- if(!(type & CLIENTWRITE_BODY)) -+ if(!(type & CLIENTWRITE_BODY) || !nbytes) - return Curl_cwriter_write(data, writer->next, type, buf, nbytes); - - failf(data, "Unrecognized content encoding type. " -diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake -index 0f4db6982..dfabbefca 100644 ---- a/lib/curl_config.h.cmake -+++ b/lib/curl_config.h.cmake -@@ -796,3 +796,6 @@ ${SIZEOF_TIME_T_CODE} - - /* Define to 1 to enable TLS-SRP support. */ - #cmakedefine USE_TLS_SRP 1 -+ -+/* if ECH support is available */ -+#cmakedefine USE_ECH 1 -diff --git a/lib/dynhds.c b/lib/dynhds.c -index d7548959b..00f97506b 100644 ---- a/lib/dynhds.c -+++ b/lib/dynhds.c -@@ -56,6 +56,8 @@ entry_new(const char *name, size_t namelen, - e->valuelen = valuelen; - if(opts & DYNHDS_OPT_LOWERCASE) - Curl_strntolower(e->name, e->name, e->namelen); -+ if(opts & DYNHDS_OPT_LOWERCASE_VAL) -+ Curl_strntolower(e->value, e->value, e->valuelen); - return e; - } - -@@ -138,6 +140,16 @@ void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts) - dynhds->opts = opts; - } - -+void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt) -+{ -+ dynhds->opts |= opt; -+} -+ -+void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt) -+{ -+ dynhds->opts &= ~opt; -+} -+ - struct dynhds_entry *Curl_dynhds_getn(struct dynhds *dynhds, size_t n) - { - DEBUGASSERT(dynhds); -diff --git a/lib/dynhds.h b/lib/dynhds.h -index 3b536000a..d7135698f 100644 ---- a/lib/dynhds.h -+++ b/lib/dynhds.h -@@ -53,6 +53,7 @@ struct dynhds { - - #define DYNHDS_OPT_NONE (0) - #define DYNHDS_OPT_LOWERCASE (1 << 0) -+#define DYNHDS_OPT_LOWERCASE_VAL (1 << 1) - - /** - * Init for use on first time or after a reset. -@@ -82,6 +83,8 @@ size_t Curl_dynhds_count(struct dynhds *dynhds); - * This will not have an effect on already existing headers. - */ - void Curl_dynhds_set_opts(struct dynhds *dynhds, int opts); -+void Curl_dynhds_set_opt(struct dynhds *dynhds, int opt); -+void Curl_dynhds_del_opt(struct dynhds *dynhds, int opt); - - /** - * Return the n-th header entry or NULL if it does not exist. -diff --git a/lib/easy.c b/lib/easy.c -index dc4870608..4746133e9 100644 ---- a/lib/easy.c -+++ b/lib/easy.c -@@ -75,6 +75,8 @@ - #include "dynbuf.h" - #include "altsvc.h" - #include "hsts.h" -+#include "strcase.h" -+#include "impersonate.h" - - #include "easy_lock.h" - -@@ -342,6 +344,221 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - return rc; - } - -+ -+/* -+ * curl-impersonate: -+ * Actually call curl_easy_setopt() with all the needed options -+ * */ -+static CURLcode _do_impersonate(struct Curl_easy *data, -+ const struct impersonate_opts *opts, -+ int default_headers) -+{ -+ int i; -+ int ret; -+ struct curl_slist *headers = NULL; -+ -+ if(opts->target == NULL) { -+ DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", -+ opts->target)); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ -+ if(opts->httpversion != CURL_HTTP_VERSION_NONE) { -+ ret = curl_easy_setopt(data, CURLOPT_HTTP_VERSION, opts->httpversion); -+ if(ret) -+ return ret; -+ } -+ -+ if (opts->ssl_version != CURL_SSLVERSION_DEFAULT) { -+ ret = curl_easy_setopt(data, CURLOPT_SSLVERSION, opts->ssl_version); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->ciphers) { -+ ret = curl_easy_setopt(data, CURLOPT_SSL_CIPHER_LIST, opts->ciphers); -+ if (ret) -+ return ret; -+ } -+ -+ if(opts->curves) { -+ ret = curl_easy_setopt(data, CURLOPT_SSL_EC_CURVES, opts->curves); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->sig_hash_algs) { -+ ret = curl_easy_setopt(data, CURLOPT_SSL_SIG_HASH_ALGS, -+ opts->sig_hash_algs); -+ if(ret) -+ return ret; -+ } -+ -+ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_NPN, opts->npn ? 1 : 0); -+ if(ret) -+ return ret; -+ -+ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_ALPN, opts->alpn ? 1 : 0); -+ if(ret) -+ return ret; -+ -+ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_ALPS, opts->alps ? 1 : 0); -+ if(ret) -+ return ret; -+ -+ ret = curl_easy_setopt(data, CURLOPT_SSL_ENABLE_TICKET, -+ opts->tls_session_ticket ? 1 : 0); -+ if(ret) -+ return ret; -+ -+ // always enable this for browsers -+ ret = curl_easy_setopt(data, CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, 1); -+ if(ret) -+ return ret; -+ -+ // always enable this for browsers -+ ret = curl_easy_setopt(data, CURLOPT_TLS_STATUS_REQUEST, 1); -+ if(ret) -+ return ret; -+ -+ if(opts->tls_permute_extensions) { -+ ret = curl_easy_setopt(data, CURLOPT_SSL_PERMUTE_EXTENSIONS, 1); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->cert_compression) { -+ ret = curl_easy_setopt(data, -+ CURLOPT_SSL_CERT_COMPRESSION, -+ opts->cert_compression); -+ if(ret) -+ return ret; -+ } -+ -+ if(default_headers) { -+ /* Build a linked list out of the static array of headers. */ -+ for(i = 0; i < IMPERSONATE_MAX_HEADERS; i++) { -+ if(opts->http_headers[i]) { -+ headers = curl_slist_append(headers, opts->http_headers[i]); -+ if(!headers) { -+ return CURLE_OUT_OF_MEMORY; -+ } -+ } -+ } -+ -+ if(headers) { -+ ret = curl_easy_setopt(data, CURLOPT_HTTPBASEHEADER, headers); -+ curl_slist_free_all(headers); -+ if(ret) -+ return ret; -+ } -+ } -+ -+ if(opts->http2_pseudo_headers_order) { -+ ret = curl_easy_setopt(data, -+ CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, -+ opts->http2_pseudo_headers_order); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->http2_settings) { -+ ret = curl_easy_setopt(data, CURLOPT_HTTP2_SETTINGS, opts->http2_settings); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->http2_window_update) { -+ ret = curl_easy_setopt(data, CURLOPT_HTTP2_WINDOW_UPDATE, opts->http2_window_update); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->http2_streams) { -+ ret = curl_easy_setopt(data, CURLOPT_HTTP2_STREAMS, opts->http2_streams); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->ech) { -+ ret = curl_easy_setopt(data, CURLOPT_ECH, opts->ech); -+ if(ret) -+ return ret; -+ } -+ -+ if(opts->tls_grease) { -+ ret = curl_easy_setopt(data, CURLOPT_TLS_GREASE, opts->tls_grease); -+ } -+ -+ if(opts->tls_extension_order) { -+ // printf("setting extension order as: %s\n", opts->tls_extension_order); -+ ret = curl_easy_setopt(data, CURLOPT_TLS_EXTENSION_ORDER, opts->tls_extension_order); -+ } -+ -+ if(opts->http2_stream_weight) { -+ ret = curl_easy_setopt(data, CURLOPT_STREAM_WEIGHT, opts->http2_stream_weight); -+ } -+ -+ if(opts->http2_stream_exclusive) { -+ ret = curl_easy_setopt(data, CURLOPT_STREAM_EXCLUSIVE, opts->http2_stream_exclusive); -+ } -+ -+ /* Always enable all supported compressions. */ -+ ret = curl_easy_setopt(data, CURLOPT_ACCEPT_ENCODING, ""); -+ if(ret) -+ return ret; -+ -+ return CURLE_OK; -+} -+ -+ -+/* -+ * curl-impersonate: -+ * Call curl_easy_setopt() with all the needed options as defined by the target -+ * */ -+CURLcode curl_easy_impersonate_customized(struct Curl_easy *data, -+ const struct impersonate_opts *opts, -+ int default_headers) -+{ -+ int ret; -+ -+ ret = _do_impersonate(data, opts, default_headers); -+ if(ret) -+ return ret; -+ -+ return CURLE_OK; -+} -+ -+/* -+ * curl-impersonate: -+ * Call curl_easy_setopt() with all the needed options as defined in the -+ * 'impersonations' array. -+ * */ -+CURLcode curl_easy_impersonate(struct Curl_easy *data, const char *target, -+ int default_headers) -+{ -+ int ret; -+ const struct impersonate_opts *opts = NULL; -+ -+ for(opts = impersonations; opts->target != NULL; opts++) { -+ if (strcasecompare(target, opts->target)) { -+ break; -+ } -+ } -+ -+ if(opts->target == NULL) { -+ DEBUGF(fprintf(stderr, "Error: unknown impersonation target '%s'\n", -+ target)); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ -+ ret = _do_impersonate(data, opts, default_headers); -+ if(ret) -+ return ret; -+ -+ return CURLE_OK; -+} -+ - /* - * curl_easy_init() is the external interface to alloc, setup and init an - * easy handle that is returned. If anything goes wrong, NULL is returned. -@@ -350,6 +567,8 @@ struct Curl_easy *curl_easy_init(void) - { - CURLcode result; - struct Curl_easy *data; -+ char *env_target; -+ char *env_headers; - - /* Make sure we inited the global SSL stuff */ - global_init_lock(); -@@ -372,6 +591,29 @@ struct Curl_easy *curl_easy_init(void) - return NULL; - } - -+ /* -+ * curl-impersonate: Hook into curl_easy_init() to set the required options -+ * from an environment variable. -+ * This is a bit hacky but allows seamless integration of libcurl-impersonate -+ * without code modifications to the app. -+ */ -+ env_target = curl_getenv("CURL_IMPERSONATE"); -+ if(env_target) { -+ env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); -+ if(env_headers) { -+ result = curl_easy_impersonate(data, env_target, -+ !strcasecompare(env_headers, "no")); -+ free(env_headers); -+ } else { -+ result = curl_easy_impersonate(data, env_target, true); -+ } -+ free(env_target); -+ if(result) { -+ Curl_close(&data); -+ return NULL; -+ } -+ } -+ - return data; - } - -@@ -952,6 +1194,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) - outcurl->state.referer_alloc = TRUE; - } - -+ if(data->state.base_headers) { -+ outcurl->state.base_headers = -+ Curl_slist_duplicate(data->state.base_headers); -+ if(!outcurl->state.base_headers) -+ goto fail; -+ } -+ - /* Reinitialize an SSL engine for the new handle - * note: the engine name has already been copied by dupset */ - if(outcurl->set.str[STRING_SSL_ENGINE]) { -@@ -1040,6 +1289,9 @@ fail: - */ - void curl_easy_reset(struct Curl_easy *data) - { -+ char *env_target; -+ char *env_headers; -+ - Curl_req_hard_reset(&data->req, data); - - /* zero out UserDefined data: */ -@@ -1064,6 +1316,23 @@ void curl_easy_reset(struct Curl_easy *data) - #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH) - Curl_http_auth_cleanup_digest(data); - #endif -+ -+ /* -+ * curl-impersonate: Hook into curl_easy_reset() to set the required options -+ * from an environment variable, just like in curl_easy_init(). -+ */ -+ env_target = curl_getenv("CURL_IMPERSONATE"); -+ if(env_target) { -+ env_headers = curl_getenv("CURL_IMPERSONATE_HEADERS"); -+ if(env_headers) { -+ curl_easy_impersonate(data, env_target, -+ !strcasecompare(env_headers, "no")); -+ free(env_headers); -+ } else { -+ curl_easy_impersonate(data, env_target, true); -+ } -+ free(env_target); -+ } - } - - /* -diff --git a/lib/easyoptions.c b/lib/easyoptions.c -index 9c4438a10..86068cf12 100644 ---- a/lib/easyoptions.c -+++ b/lib/easyoptions.c -@@ -86,6 +86,7 @@ struct curl_easyoption Curl_easyopts[] = { - {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0}, - {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, - {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0}, -+ {"ECH", CURLOPT_ECH, CURLOT_STRING, 0}, - {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0}, - {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS}, - {"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0}, -@@ -133,8 +134,14 @@ struct curl_easyoption Curl_easyopts[] = { - {"HSTS_CTRL", CURLOPT_HSTS_CTRL, CURLOT_LONG, 0}, - {"HTTP09_ALLOWED", CURLOPT_HTTP09_ALLOWED, CURLOT_LONG, 0}, - {"HTTP200ALIASES", CURLOPT_HTTP200ALIASES, CURLOT_SLIST, 0}, -+ {"HTTP2_PSEUDO_HEADERS_ORDER", CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, -+ CURLOT_STRING, 0}, -+ {"HTTP2_SETTINGS", CURLOPT_HTTP2_SETTINGS, CURLOT_STRING, 0}, -+ {"HTTP2_STREAMS", CURLOPT_HTTP2_STREAMS, CURLOT_STRING, 0}, -+ {"HTTP2_WINDOW_UPDATE", CURLOPT_HTTP2_WINDOW_UPDATE, CURLOT_LONG, 0}, - {"HTTPAUTH", CURLOPT_HTTPAUTH, CURLOT_VALUES, 0}, - {"HTTPGET", CURLOPT_HTTPGET, CURLOT_LONG, 0}, -+ {"HTTPBASEHEADER", CURLOPT_HTTPBASEHEADER, CURLOT_SLIST, 0}, - {"HTTPHEADER", CURLOPT_HTTPHEADER, CURLOT_SLIST, 0}, - {"HTTPPOST", CURLOPT_HTTPPOST, CURLOT_OBJECT, 0}, - {"HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL, CURLOT_LONG, 0}, -@@ -307,21 +314,27 @@ struct curl_easyoption Curl_easyopts[] = { - {"SSLKEYTYPE", CURLOPT_SSLKEYTYPE, CURLOT_STRING, 0}, - {"SSLKEY_BLOB", CURLOPT_SSLKEY_BLOB, CURLOT_BLOB, 0}, - {"SSLVERSION", CURLOPT_SSLVERSION, CURLOT_VALUES, 0}, -+ {"SSL_CERT_COMPRESSION", CURLOPT_SSL_CERT_COMPRESSION, CURLOT_STRING, 0}, - {"SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST, CURLOT_STRING, 0}, - {"SSL_CTX_DATA", CURLOPT_SSL_CTX_DATA, CURLOT_CBPTR, 0}, - {"SSL_CTX_FUNCTION", CURLOPT_SSL_CTX_FUNCTION, CURLOT_FUNCTION, 0}, - {"SSL_EC_CURVES", CURLOPT_SSL_EC_CURVES, CURLOT_STRING, 0}, - {"SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN, CURLOT_LONG, 0}, -+ {"SSL_ENABLE_ALPS", CURLOPT_SSL_ENABLE_ALPS, CURLOT_LONG, 0}, - {"SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN, CURLOT_LONG, 0}, -+ {"SSL_ENABLE_TICKET", CURLOPT_SSL_ENABLE_TICKET, CURLOT_LONG, 0}, - {"SSL_FALSESTART", CURLOPT_SSL_FALSESTART, CURLOT_LONG, 0}, - {"SSL_OPTIONS", CURLOPT_SSL_OPTIONS, CURLOT_VALUES, 0}, -+ {"SSL_PERMUTE_EXTENSIONS", CURLOPT_SSL_PERMUTE_EXTENSIONS, CURLOT_LONG, 0}, - {"SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE, CURLOT_LONG, 0}, -+ {"SSL_SIG_HASH_ALGS", CURLOPT_SSL_SIG_HASH_ALGS, CURLOT_STRING, 0}, - {"SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST, CURLOT_LONG, 0}, - {"SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER, CURLOT_LONG, 0}, - {"SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS, CURLOT_LONG, 0}, - {"STDERR", CURLOPT_STDERR, CURLOT_OBJECT, 0}, - {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0}, - {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0}, -+ {"STREAM_EXCLUSIVE", CURLOPT_STREAM_EXCLUSIVE, CURLOT_LONG, 0}, - {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0}, - {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS, - CURLOT_LONG, 0}, -@@ -342,6 +355,11 @@ struct curl_easyoption Curl_easyopts[] = { - {"TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD, CURLOT_STRING, 0}, - {"TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE, CURLOT_STRING, 0}, - {"TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME, CURLOT_STRING, 0}, -+ {"TLS_EXTENSION_ORDER", CURLOPT_TLS_EXTENSION_ORDER, CURLOT_STRING, 0}, -+ {"TLS_GREASE", CURLOPT_TLS_GREASE, CURLOT_LONG, 0}, -+ {"TLS_KEY_USAGE_NO_CHECK", CURLOPT_TLS_KEY_USAGE_NO_CHECK, CURLOT_LONG, 0}, -+ {"TLS_SIGNED_CERT_TIMESTAMPS", CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, CURLOT_LONG, 0}, -+ {"TLS_STATUS_REQUEST", CURLOPT_TLS_STATUS_REQUEST, CURLOT_LONG, 0}, - {"TRAILERDATA", CURLOPT_TRAILERDATA, CURLOT_CBPTR, 0}, - {"TRAILERFUNCTION", CURLOPT_TRAILERFUNCTION, CURLOT_FUNCTION, 0}, - {"TRANSFERTEXT", CURLOPT_TRANSFERTEXT, CURLOT_LONG, 0}, -@@ -375,6 +393,6 @@ struct curl_easyoption Curl_easyopts[] = { - */ - int Curl_easyopts_check(void) - { -- return ((CURLOPT_LASTENTRY%10000) != (324 + 1)); -+ return ((CURLOPT_LASTENTRY%10000) != (1013 + 1)); - } - #endif -diff --git a/lib/http.c b/lib/http.c -index 92c04e69c..84ece2a16 100644 ---- a/lib/http.c -+++ b/lib/http.c -@@ -91,6 +91,7 @@ - #include "ws.h" - #include "c-hyper.h" - #include "curl_ctype.h" -+#include "slist.h" - - /* The last 3 #include files should be in this order */ - #include "curl_printf.h" -@@ -1451,6 +1452,15 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, - int numlists = 1; /* by default */ - int i; - -+ /* -+ * curl-impersonate: Use the merged list of headers if it exists (i.e. when -+ * the CURLOPT_HTTPBASEHEADER option was set. -+ */ -+ struct curl_slist *noproxyheaders = -+ (data->state.merged_headers ? -+ data->state.merged_headers : -+ data->set.headers); -+ - #ifndef CURL_DISABLE_PROXY - enum proxy_use proxy; - -@@ -1462,10 +1472,10 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, - - switch(proxy) { - case HEADER_SERVER: -- h[0] = data->set.headers; -+ h[0] = noproxyheaders; - break; - case HEADER_PROXY: -- h[0] = data->set.headers; -+ h[0] = noproxyheaders; - if(data->set.sep_headers) { - h[1] = data->set.proxyheaders; - numlists++; -@@ -1475,12 +1485,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, - if(data->set.sep_headers) - h[0] = data->set.proxyheaders; - else -- h[0] = data->set.headers; -+ h[0] = noproxyheaders; - break; - } - #else - (void)is_connect; -- h[0] = data->set.headers; -+ h[0] = noproxyheaders; - #endif - - /* loop through one or two lists */ -@@ -1717,6 +1727,108 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, - *reqp = httpreq; - } - -+/* -+ * curl-impersonate: -+ * Create a new linked list of headers. -+ * The new list is a merge between the "base" headers and the application given -+ * headers. The "base" headers contain curl-impersonate's list of headers -+ * used by default by the impersonated browser. -+ * -+ * The application given headers will override the "base" headers if supplied. -+ */ -+CURLcode Curl_http_merge_headers(struct Curl_easy *data) -+{ -+ int i; -+ int ret; -+ struct curl_slist *head; -+ struct curl_slist *dup = NULL; -+ struct curl_slist *new_list = NULL; -+ char *uagent; -+ -+ if (!data->state.base_headers) -+ return CURLE_OK; -+ -+ /* Duplicate the list for temporary use. */ -+ if (data->set.headers) { -+ dup = Curl_slist_duplicate(data->set.headers); -+ if(!dup) -+ return CURLE_OUT_OF_MEMORY; -+ } -+ -+ for(head = data->state.base_headers; head; head = head->next) { -+ char *sep; -+ size_t prefix_len; -+ bool found = FALSE; -+ struct curl_slist *head2; -+ -+ sep = strchr(head->data, ':'); -+ if(!sep) -+ continue; -+ -+ prefix_len = sep - head->data; -+ -+ /* Check if this header was added by the application. */ -+ for(head2 = dup; head2; head2 = head2->next) { -+ if(head2->data && -+ strncasecompare(head2->data, head->data, prefix_len) && -+ Curl_headersep(head2->data[prefix_len]) ) { -+ new_list = curl_slist_append(new_list, head2->data); -+ /* Free and set to NULL to mark that it's been added. */ -+ Curl_safefree(head2->data); -+ found = TRUE; -+ break; -+ } -+ } -+ -+ /* If the user agent was set with CURLOPT_USERAGENT, but not with -+ * CURLOPT_HTTPHEADER, take it from there instead. */ -+ if(!found && -+ strncasecompare(head->data, "User-Agent", prefix_len) && -+ data->set.str[STRING_USERAGENT] && -+ *data->set.str[STRING_USERAGENT]) { -+ uagent = aprintf("User-Agent: %s", data->set.str[STRING_USERAGENT]); -+ if(!uagent) { -+ ret = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ new_list = Curl_slist_append_nodup(new_list, uagent); -+ found = TRUE; -+ } -+ -+ if (!found) { -+ new_list = curl_slist_append(new_list, head->data); -+ } -+ -+ if (!new_list) { -+ ret = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ } -+ -+ /* Now go over any additional application-supplied headers. */ -+ for(head = dup; head; head = head->next) { -+ if(head->data) { -+ new_list = curl_slist_append(new_list, head->data); -+ if(!new_list) { -+ ret = CURLE_OUT_OF_MEMORY; -+ goto fail; -+ } -+ } -+ } -+ -+ curl_slist_free_all(dup); -+ /* Save the new, merged list separately, so it can be freed later. */ -+ curl_slist_free_all(data->state.merged_headers); -+ data->state.merged_headers = new_list; -+ -+ return CURLE_OK; -+ -+fail: -+ Curl_safefree(dup); -+ curl_slist_free_all(new_list); -+ return ret; -+} -+ - CURLcode Curl_http_useragent(struct Curl_easy *data) - { - /* The User-Agent string might have been allocated in url.c already, because -@@ -2558,6 +2670,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) - if(result) - goto fail; - -+ /* curl-impersonate: Add HTTP headers to impersonate real browsers. */ -+ result = Curl_http_merge_headers(data); -+ if (result) -+ return result; -+ - result = Curl_http_host(data, conn); - if(result) - goto fail; -@@ -4269,12 +4386,41 @@ static bool h2_non_field(const char *name, size_t namelen) - return FALSE; - } - -+/* -+ * curl-impersonate: -+ * Determine the position of HTTP/2 pseudo headers. -+ * The pseudo headers ":method", ":path", ":scheme", ":authority" -+ * are sent in different order by different browsers. An important part of the -+ * impersonation is ordering them like the browser does. -+ */ -+static CURLcode h2_check_pseudo_header_order(const char *order) -+{ -+ if(strlen(order) != 4) -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ // :method should always be first -+ if(order[0] != 'm') -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ // All pseudo-headers must be present -+ if(!strchr(order, 'm') || -+ !strchr(order, 'a') || -+ !strchr(order, 's') || -+ !strchr(order, 'p')) -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ -+ return CURLE_OK; -+} -+ - CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, - struct httpreq *req, struct Curl_easy *data) - { - const char *scheme = NULL, *authority = NULL; - struct dynhds_entry *e; - size_t i; -+ // Use the Chrome ordering by default: -+ // :method, :authority, :scheme, :path -+ char *order = "masp"; - CURLcode result; - - DEBUGASSERT(req); -@@ -4308,25 +4454,56 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, - - Curl_dynhds_reset(h2_headers); - Curl_dynhds_set_opts(h2_headers, DYNHDS_OPT_LOWERCASE); -- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), -- req->method, strlen(req->method)); -- if(!result && scheme) { -- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), -- scheme, strlen(scheme)); -- } -- if(!result && authority) { -- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), -- authority, strlen(authority)); -+ -+ /* curl-impersonate: order of pseudo headers is different from the default */ -+ if(data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]) { -+ order = data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER]; - } -- if(!result && req->path) { -- result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), -- req->path, strlen(req->path)); -+ -+ result = h2_check_pseudo_header_order(order); -+ -+ /* curl-impersonate: add http2 pseudo headers according to the specified order. */ -+ for(i = 0; !result && i < strlen(order); ++i) { -+ switch(order[i]) { -+ case 'm': -+ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_METHOD), -+ req->method, strlen(req->method)); -+ break; -+ case 'a': -+ if(authority) { -+ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_AUTHORITY), -+ authority, strlen(authority)); -+ } -+ break; -+ case 's': -+ if(scheme) { -+ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_SCHEME), -+ scheme, strlen(scheme)); -+ } -+ break; -+ case 'p': -+ if(req->path) { -+ result = Curl_dynhds_add(h2_headers, STRCONST(HTTP_PSEUDO_PATH), -+ req->path, strlen(req->path)); -+ } -+ break; -+ } - } -+ - for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) { - e = Curl_dynhds_getn(&req->headers, i); - if(!h2_non_field(e->name, e->namelen)) { -+ /* curl-impersonate: -+ * Some HTTP/2 servers reject 'te' header value that is not lowercase (e.g. 'Trailers). -+ * Convert to lowercase explicitly. -+ */ -+ if(e->namelen == 2 && strcasecompare(e->name, "te")) -+ Curl_dynhds_set_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); -+ - result = Curl_dynhds_add(h2_headers, e->name, e->namelen, - e->value, e->valuelen); -+ -+ Curl_dynhds_del_opt(h2_headers, DYNHDS_OPT_LOWERCASE_VAL); - } - } - -diff --git a/lib/http2.c b/lib/http2.c -index 99d7f3b0e..88419cfca 100644 ---- a/lib/http2.c -+++ b/lib/http2.c -@@ -51,6 +51,7 @@ - #include "curl_printf.h" - #include "curl_memory.h" - #include "memdebug.h" -+#include "rand.h" - - #if (NGHTTP2_VERSION_NUM < 0x010c00) - #error too old nghttp2 version, upgrade! -@@ -69,7 +70,7 @@ - * use 16K as chunk size, as that fits H2 DATA frames well */ - #define H2_CHUNK_SIZE (16 * 1024) - /* this is how much we want "in flight" for a stream */ --#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024) -+#define H2_STREAM_WINDOW_SIZE (1024 * 1024) - /* on receiving from TLS, we prep for holding a full stream window */ - #define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) - /* on send into TLS, we just want to accumulate small frames */ -@@ -87,26 +88,99 @@ - * will block their received QUOTA in the connection window. And if we - * run out of space, the server is blocked from sending us any data. - * See #10988 for an issue with this. */ --#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE) -+/* curl-impersonate: match Chrome window size. */ -+#define HTTP2_HUGE_WINDOW_SIZE (15 * H2_STREAM_WINDOW_SIZE) - --#define H2_SETTINGS_IV_LEN 3 -+#define H2_SETTINGS_IV_LEN 8 - #define H2_BINSETTINGS_LEN 80 - -+ - static int populate_settings(nghttp2_settings_entry *iv, - struct Curl_easy *data) - { -- iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; -- iv[0].value = Curl_multi_max_concurrent_streams(data->multi); -+ // curl-impersonate: -+ // Setting http2 settings frame based on user instruction. -+ // https://httpwg.org/specs/rfc7540.html#SETTINGS -+ // Format example: 1:65536;2:0;4:6291456;6:262144 -+ -+ // TODO check if the http2 settings is valid -+ int i = 0; -+ char *delimiter = ";"; -+ -+ // Use chrome's settings as default -+ char *http2_settings = "1:65536;2:0;4:6291456;6:262144"; -+ if(data->set.str[STRING_HTTP2_SETTINGS]) { -+ http2_settings = data->set.str[STRING_HTTP2_SETTINGS]; -+ } - -- iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; -- iv[1].value = H2_STREAM_WINDOW_SIZE; -+ // printf("USING settings %s\n", http2_settings); -+ -+ char *tmp = strdup(http2_settings); -+ char *setting = strtok(tmp, delimiter); -+ -+ // loop through the string to extract all other tokens -+ while(setting != NULL) { -+ // deal with each setting -+ switch(setting[0]) { -+ case '1': -+ iv[i].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ case '2': -+ iv[i].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ case '3': -+ // FIXME We also need to notify curl_multi about this setting -+ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ case '4': -+ iv[i].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ case '5': -+ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ case '6': -+ iv[i].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ // https://tools.ietf.org/html/rfc8441 -+ case '8': -+ iv[i].settings_id = NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ // https://tools.ietf.org/html/rfc9218 -+ case '9': -+ iv[i].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES; -+ iv[i].value = atoi(setting + 2); -+ i++; -+ break; -+ } -+ setting = strtok(NULL, delimiter); -+ } -+ free(tmp); - -- iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; -- iv[2].value = data->multi->push_cb != NULL; -+ // curl-impersonate: -+ // Up until Chrome 98, there was a randomly chosen setting number in the -+ // HTTP2 SETTINGS frame. This might be something similar to TLS GREASE. -+ // However, it seems to have been removed since. -+ // Curl_rand(data, (unsigned char *)&iv[4].settings_id, sizeof(iv[4].settings_id)); -+ // Curl_rand(data, (unsigned char *)&iv[4].value, sizeof(iv[4].value)); - -- return 3; -+ return i; - } - -+ - static ssize_t populate_binsettings(uint8_t *binsettings, - struct Curl_easy *data) - { -@@ -165,6 +239,75 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) - } - } - -+static CURLcode http2_set_stream_priority(struct Curl_cfilter *cf, -+ struct Curl_easy *data, -+ int32_t stream_id, -+ int32_t dep_stream_id, -+ int32_t weight, -+ int exclusive -+ ) -+{ -+ int rv; -+ struct cf_h2_ctx *ctx = cf->ctx; -+ nghttp2_priority_spec pri_spec; -+ -+ nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive); -+ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, -+ stream_id, &pri_spec); -+ if(rv) { -+ failf(data, "nghttp2_submit_priority() failed: %s(%d)", -+ nghttp2_strerror(rv), rv); -+ return CURLE_HTTP2; -+ } -+ -+ return CURLE_OK; -+} -+ -+/* -+ * curl-impersonate: Firefox uses an elaborate scheme of http/2 streams to -+ * split the load for html/js/css/images. It builds a tree of streams with -+ * different weights (priorities) by default and communicates this to the -+ * server. Imitate that behavior. -+ */ -+static CURLcode http2_set_stream_priorities(struct Curl_cfilter *cf, -+ struct Curl_easy *data) -+{ -+ CURLcode result; -+ char *stream_delimiter = ","; -+ char *value_delimiter = ":"; -+ -+ if(!data->set.str[STRING_HTTP2_STREAMS]) -+ return CURLE_OK; -+ -+ char *tmp1 = strdup(data->set.str[STRING_HTTP2_STREAMS]); -+ char *end1; -+ char *stream = strtok_r(tmp1, stream_delimiter, &end1); -+ -+ while(stream != NULL) { -+ -+ char *tmp2 = strdup(stream); -+ char *end2; -+ -+ int32_t stream_id = atoi(strtok_r(tmp2, value_delimiter, &end2)); -+ int exclusive = atoi(strtok_r(NULL, value_delimiter, &end2)); -+ int32_t dep_stream_id = atoi(strtok_r(NULL, value_delimiter, &end2)); -+ int32_t weight = atoi(strtok_r(NULL, value_delimiter, &end2)); -+ -+ free(tmp2); -+ -+ result = http2_set_stream_priority(cf, data, stream_id, dep_stream_id, weight, exclusive); -+ if(result) { -+ free(tmp1); -+ return result; -+ } -+ -+ stream = strtok_r(NULL, stream_delimiter, &end1); -+ } -+ -+ free(tmp1); -+ return CURLE_OK; -+} -+ - static CURLcode h2_progress_egress(struct Curl_cfilter *cf, - struct Curl_easy *data); - -@@ -491,8 +634,22 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, - } - } - -- rc = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE, 0, -- HTTP2_HUGE_WINDOW_SIZE); -+ // curl-impersonate: -+ // Directly changing the initial window update using users' settings. -+ int current_window_size = nghttp2_session_get_local_window_size(ctx->h2); -+ -+ // Use chrome's value as default -+ int window_update = 15663105; -+ if(data->set.http2_window_update) { -+ window_update = data->set.http2_window_update; -+ } -+ -+ // printf("Using window update %d\n", window_update); -+ -+ rc = nghttp2_session_set_local_window_size( -+ ctx->h2, NGHTTP2_FLAG_NONE, 0, -+ current_window_size + window_update); -+ - if(rc) { - failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", - nghttp2_strerror(rc), rc); -@@ -500,6 +657,16 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf, - goto out; - } - -+ // curl-impersonate: set stream priorities -+ result = http2_set_stream_priorities(cf, data); -+ if(result) -+ goto out; -+ -+#define FIREFOX_DEFAULT_STREAM_ID (15) -+ /* Best effort to set the request's stream id to 15, like Firefox does. */ -+ // Let's ignore this for now, as it seems not to be targeted as fingerprints. -+ // nghttp2_session_set_next_stream_id(ctx->h2, FIREFOX_DEFAULT_STREAM_ID); -+ - /* all set, traffic will be send on connect */ - result = CURLE_OK; - CURL_TRC_CF(data, cf, "[0] created h2 session%s", -@@ -1716,11 +1883,19 @@ out: - return rv; - } - -+/* -+ * curl-impersonate: Use Chrome's default HTTP/2 stream weight -+ * instead of NGINX default stream weight. -+ */ -+#define CHROME_DEFAULT_STREAM_WEIGHT (256) -+#define SAFARI_DEFAULT_STREAM_WEIGHT (255) -+#define FIREFOX_DEFAULT_STREAM_WEIGHT (42) -+ - static int sweight_wanted(const struct Curl_easy *data) - { - /* 0 weight is not set by user and we take the nghttp2 default one */ - return data->set.priority.weight? -- data->set.priority.weight : NGHTTP2_DEFAULT_WEIGHT; -+ data->set.priority.weight : CHROME_DEFAULT_STREAM_WEIGHT; - } - - static int sweight_in_effect(const struct Curl_easy *data) -@@ -1736,12 +1911,23 @@ static int sweight_in_effect(const struct Curl_easy *data) - * struct. - */ - -+/* -+ * curl-impersonate: By default Firefox uses stream 13 as the "parent" of the -+ * stream that fetches the main html resource of the web page. -+ */ -+#define FIREFOX_DEFAULT_STREAM_DEP (13) -+ - static void h2_pri_spec(struct Curl_easy *data, - nghttp2_priority_spec *pri_spec) - { - struct Curl_data_priority *prio = &data->set.priority; - struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent); - int32_t depstream_id = depstream? depstream->id:0; -+ // int32_t depstream_id = depstream? depstream->id:FIREFOX_DEFAULT_STREAM_DEP; -+ -+ /* curl-impersonate: Set stream exclusive flag based on user option. -+ * Use data->set, not data->state. -+ */ - nghttp2_priority_spec_init(pri_spec, depstream_id, - sweight_wanted(data), - data->set.priority.exclusive); -@@ -1761,20 +1947,24 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, - struct h2_stream_ctx *stream = H2_STREAM_CTX(data); - int rv = 0; - -+ /* curl-impersonate: Check if stream exclusive flag is true. */ - if(stream && stream->id > 0 && - ((sweight_wanted(data) != sweight_in_effect(data)) || -- (data->set.priority.exclusive != data->state.priority.exclusive) || -- (data->set.priority.parent != data->state.priority.parent)) ) { -+ (data->set.priority.exclusive != 1) || -+ (data->set.priority.parent != data->state.priority.parent))) { - /* send new weight and/or dependency */ - nghttp2_priority_spec pri_spec; - - h2_pri_spec(data, &pri_spec); -- CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); -- DEBUGASSERT(stream->id != -1); -- rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, -- stream->id, &pri_spec); -- if(rv) -- goto out; -+ /* curl-impersonate: Don't send PRIORITY frames for main stream. */ -+ if(stream->id != 1) { -+ CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id); -+ DEBUGASSERT(stream->id != -1); -+ rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE, -+ stream->id, &pri_spec); -+ if(rv) -+ goto out; -+ } - } - - ctx->nw_out_blocked = 0; -diff --git a/lib/http2.h b/lib/http2.h -index 80e183480..8ee390b7e 100644 ---- a/lib/http2.h -+++ b/lib/http2.h -@@ -31,7 +31,8 @@ - - /* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting - from the peer */ --#define DEFAULT_MAX_CONCURRENT_STREAMS 100 -+/* curl-impersonate: Use 1000 concurrent streams like Chrome. */ -+#define DEFAULT_MAX_CONCURRENT_STREAMS 1000 - - /* - * Store nghttp2 version info in this buffer. -diff --git a/lib/impersonate.c b/lib/impersonate.c -new file mode 100644 -index 000000000..525e61ff1 ---- /dev/null -+++ b/lib/impersonate.c -@@ -0,0 +1,1177 @@ -+#include "curl_setup.h" -+ -+#include -+ -+#include "impersonate.h" -+ -+const struct impersonate_opts impersonations[] = { -+ { -+ .target = "chrome99", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Google Chrome\";v=\"99\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome100", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Google Chrome\";v=\"100\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome101", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Google Chrome\";v=\"101\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome104", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Chromium\";v=\"104\", \" Not A;Brand\";v=\"99\", \"Google Chrome\";v=\"104\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome107", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Google Chrome\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome110", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Chromium\";v=\"110\", \"Not A(Brand\";v=\"24\", \"Google Chrome\";v=\"110\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome116", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome119", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"macOS\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .ech = "GREASE", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome120", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"macOS\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .ech = "GREASE", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome123", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Google Chrome\";v=\"123\", \"Not:A-Brand\";v=\"8\", \"Chromium\";v=\"123\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"macOS\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br, zstd", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;2:0;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .ech = "GREASE", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome124", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .curves = "X25519Kyber768Draft00:X25519:P-256:P-384", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Chromium\";v=\"124\", \"Google Chrome\";v=\"124\", \"Not-A.Brand\";v=\"99\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"macOS\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br, zstd", -+ "Accept-Language: en-US,en;q=0.9", -+ "Priority: u=0, i" -+ }, -+ .http2_settings = "1:65536;2:0;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .ech = "GREASE", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome131", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .curves = "X25519MLKEM768:X25519:P-256:P-384", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_permute_extensions = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"macOS\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br, zstd", -+ "Accept-Language: en-US,en;q=0.9", -+ "Priority: u=0, i" -+ }, -+ .http2_settings = "1:65536;2:0;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .ech = "GREASE", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "chrome99_android", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Google Chrome\";v=\"99\"", -+ "sec-ch-ua-mobile: ?1", -+ "sec-ch-ua-platform: \"Android\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.58 Mobile Safari/537.36", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "edge99", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"99\", \"Microsoft Edge\";v=\"99\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36 Edg/99.0.1150.30", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "edge101", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "ECDHE-ECDSA-AES128-GCM-SHA256," -+ "ECDHE-RSA-AES128-GCM-SHA256," -+ "ECDHE-ECDSA-AES256-GCM-SHA384," -+ "ECDHE-RSA-AES256-GCM-SHA384," -+ "ECDHE-ECDSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-CHACHA20-POLY1305," -+ "ECDHE-RSA-AES128-SHA," -+ "ECDHE-RSA-AES256-SHA," -+ "AES128-GCM-SHA256," -+ "AES256-GCM-SHA384," -+ "AES128-SHA," -+ "AES256-SHA", -+ .npn = false, -+ .alpn = true, -+ .alps = true, -+ .tls_session_ticket = true, -+ .cert_compression = "brotli", -+ .http_headers = { -+ "sec-ch-ua: \" Not A;Brand\";v=\"99\", \"Chromium\";v=\"101\", \"Microsoft Edge\";v=\"101\"", -+ "sec-ch-ua-mobile: ?0", -+ "sec-ch-ua-platform: \"Windows\"", -+ "Upgrade-Insecure-Requests: 1", -+ "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.47", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-User: ?1", -+ "Sec-Fetch-Dest: document", -+ "Accept-Encoding: gzip, deflate, br", -+ "Accept-Language: en-US,en;q=0.9" -+ }, -+ .http2_settings = "1:65536;3:1000;4:6291456;6:262144", -+ .http2_window_update = 15663105, -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 1, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari15_3", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA256," -+ "TLS_RSA_WITH_AES_128_CBC_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA,", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "ecdsa_sha1," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .http_headers = { -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Safari/605.1.15", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Accept-Language: en-us", -+ "Accept-Encoding: gzip, deflate, br" -+ }, -+ .http2_settings = "4:4194304;3:100", -+ .http2_window_update = 10485760, -+ .http2_pseudo_headers_order = "mspa", -+ .http2_stream_weight = 255, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari15_5", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "ecdsa_sha1," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Accept-Language: en-GB,en-US;q=0.9,en;q=0.8", -+ "Accept-Encoding: gzip, deflate, br" -+ }, -+ .http2_settings = "4:4194304;3:100", -+ .http2_window_update = 10485760, -+ .http2_pseudo_headers_order = "mspa", -+ .http2_stream_weight = 255, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari17_2_ios", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "ecdsa_sha1," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Sec-Fetch-Site: none", -+ "Accept-Encoding: gzip, deflate, br", -+ "Sec-Fetch-Mode: navigate", -+ "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1", -+ "Accept-Language: en-US,en;q=0.9", -+ "Sec-Fetch-Dest: document" -+ }, -+ .http2_settings = "2:0;4:2097152;3:100", -+ .http2_window_update = 10485760, -+ .http2_pseudo_headers_order = "mspa", -+ .http2_stream_weight = 255, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari18_0_ios", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "sec-fetch-dest: document", -+ "user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1", -+ "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "sec-fetch-site: none", -+ "sec-fetch-mode: navigate", -+ "accept-language: en-US,en;q=0.9", -+ "priority: u=0, i", -+ "accept-encoding: gzip, deflate, br" -+ }, -+ .http2_settings = "2:0;3:100;4:2097152;8:1;9:1", -+ .http2_window_update = 10420225, -+ .http2_pseudo_headers_order = "msap", -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari17_0", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "ecdsa_sha1," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Sec-Fetch-Site: none", -+ "Accept-Encoding: gzip, deflate, br", -+ "Sec-Fetch-Mode: navigate", -+ "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", -+ "Accept-Language: en-US,en;q=0.9", -+ "Sec-Fetch-Dest: document" -+ }, -+ .http2_settings = "2:0;4:4194304;3:100", -+ .http2_window_update = 10485760, -+ .http2_pseudo_headers_order = "mspa", -+ .http2_stream_weight = 255, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "safari18_0", -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "sec-fetch-dest: document", -+ "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15", -+ "accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "sec-fetch-site: none", -+ "sec-fetch-mode: navigate", -+ "accept-language: en-US,en;q=0.9", -+ "priority: u=0, i", -+ "accept-encoding: gzip, deflate, br" -+ }, -+ .http2_settings = "2:0;3:100;4:2097152;8:1;9:1", -+ .http2_window_update = 10420225, -+ .http2_pseudo_headers_order = "msap", -+ .http2_stream_weight = 256, -+ .http2_stream_exclusive = 0, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "okhttp4", /* not working */ -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA," -+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", -+ .curves = "X25519:P-256:P-384:P-521", -+ .sig_hash_algs = -+ "ecdsa_secp256r1_sha256," -+ "rsa_pss_rsae_sha256," -+ "rsa_pkcs1_sha256," -+ "ecdsa_secp384r1_sha384," -+ "ecdsa_sha1," -+ "rsa_pss_rsae_sha384," -+ "rsa_pss_rsae_sha384," -+ "rsa_pkcs1_sha384," -+ "rsa_pss_rsae_sha512," -+ "rsa_pkcs1_sha512," -+ "rsa_pkcs1_sha1", -+ .npn = false, -+ .alpn = true, -+ .alps = false, -+ .tls_session_ticket = false, -+ .cert_compression = "zlib", -+ .http_headers = { -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", -+ "Sec-Fetch-Site: none", -+ "Accept-Encoding: gzip, deflate, br", -+ "Sec-Fetch-Mode: navigate", -+ "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15", -+ "Accept-Language: en-US,en;q=0.9", -+ "Sec-Fetch-Dest: document" -+ }, -+ .http2_settings = "2:0;4:4194304;3:100", -+ .http2_window_update = 10485760, -+ .http2_pseudo_headers_order = "mspa", -+ .http2_stream_weight = 255, -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ .target = "firefox120", /* not working */ -+ .httpversion = CURL_HTTP_VERSION_2_0, -+ .ssl_version = CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT, -+ .ciphers = -+ "TLS_AES_128_GCM_SHA256," -+ "TLS_CHACHA20_POLY1305_SHA256," -+ "TLS_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA," -+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA," -+ "TLS_RSA_WITH_AES_128_GCM_SHA256," -+ "TLS_RSA_WITH_AES_256_GCM_SHA384," -+ "TLS_RSA_WITH_AES_128_CBC_SHA," -+ "TLS_RSA_WITH_AES_256_CBC_SHA", -+ .http_headers = { -+ "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0", -+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", -+ "Accept-Language: en-US,en;q=0.5", -+ "Accept-Encoding: gzip, deflate, br", -+ "Upgrade-Insecure-Requests: 1", -+ "Sec-Fetch-Dest: document", -+ "Sec-Fetch-Mode: navigate", -+ "Sec-Fetch-Site: none", -+ "Sec-Fetch-User: ?1", -+ "Te: trailers" -+ }, -+ .http2_settings = "1:65536;4:131072;5:16384", -+ .http2_window_update = 12517377, -+ .http2_pseudo_headers_order = "mpas", -+ .http2_streams = "3:0:0:201,5:0:0:101,7:0:0:1,9:0:7:1,11:0:3:1,13:0:0:241", -+ .tls_extension_order = NULL, -+ .tls_grease = true -+ }, -+ { -+ /* Last one must be NULL. */ -+ .target = NULL -+ } -+}; -diff --git a/lib/impersonate.h b/lib/impersonate.h -new file mode 100644 -index 000000000..988a7f86a ---- /dev/null -+++ b/lib/impersonate.h -@@ -0,0 +1,52 @@ -+#ifndef HEADER_CURL_IMPERSONATE_H -+#define HEADER_CURL_IMPERSONATE_H -+ -+#define IMPERSONATE_MAX_HEADERS 32 -+ -+/* -+ * curl-impersonate: Options to be set for each supported target browser. -+ */ -+struct impersonate_opts { -+ const char *target; -+ int httpversion; -+ int ssl_version; -+ const char *ciphers; -+ /* Elliptic curves (TLS extension 10). -+ * Passed to CURLOPT_SSL_EC_CURVES */ -+ const char *curves; -+ /* Signature hash algorithms (TLS extension 13). -+ * Passed to CURLOPT_SSL_SIG_HASH_ALGS */ -+ const char *sig_hash_algs; -+ /* Enable TLS NPN extension. */ -+ bool npn; -+ /* Enable TLS ALPN extension. */ -+ bool alpn; -+ /* Enable TLS ALPS extension. */ -+ bool alps; -+ /* Enable TLS session ticket extension. */ -+ bool tls_session_ticket; -+ /* TLS certificate compression algorithms. -+ * (TLS extension 27) */ -+ const char *cert_compression; -+ const char *http_headers[IMPERSONATE_MAX_HEADERS]; -+ const char *http2_pseudo_headers_order; -+ const char *http2_settings; -+ int http2_window_update; -+ const char *http2_streams; -+ bool tls_permute_extensions; -+ const char *ech; -+ const char *tls_extension_order; -+ bool tls_grease; -+ int http2_stream_weight; -+ int http2_stream_exclusive; -+ /* Other TLS options will come here in the future once they are -+ * configurable through curl_easy_setopt() */ -+}; -+ -+/* -+ * curl-impersonate: Global array of supported browsers and their -+ * impersonation options. -+ */ -+extern const struct impersonate_opts impersonations[]; -+ -+#endif /* HEADER_CURL_IMPERSONATE_H */ -diff --git a/lib/multi.c b/lib/multi.c -index ed9cac796..6ca666e4a 100644 ---- a/lib/multi.c -+++ b/lib/multi.c -@@ -401,7 +401,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ - Curl_llist_init(&multi->msgsent, NULL); - - multi->multiplexing = TRUE; -- multi->max_concurrent_streams = 100; -+ /* curl-impersonate: Use 1000 concurrent streams like Chrome. */ -+ multi->max_concurrent_streams = 1000; - - #ifdef USE_WINSOCK - multi->wsa_event = WSACreateEvent(); -diff --git a/lib/setopt.c b/lib/setopt.c -index 8a5a5d7c3..feddeeccb 100644 ---- a/lib/setopt.c -+++ b/lib/setopt.c -@@ -51,6 +51,7 @@ - #include "altsvc.h" - #include "hsts.h" - #include "tftp.h" -+#include "slist.h" - #include "strdup.h" - /* The last 3 #include files should be in this order */ - #include "curl_printf.h" -@@ -717,6 +718,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - va_arg(param, char *)); - break; - -+ case CURLOPT_HTTPBASEHEADER: -+ /* -+ * curl-impersonate: -+ * Set a list of "base" headers. These will be merged with any headers -+ * set by CURLOPT_HTTPHEADER. curl-impersonate uses this option in order -+ * to set a list of default browser headers. -+ * -+ * Unlike CURLOPT_HTTPHEADER, -+ * the list is copied and can be immediately freed by the user. -+ */ -+ curl_slist_free_all(data->state.base_headers); -+ data->state.base_headers = \ -+ Curl_slist_duplicate(va_arg(param, struct curl_slist *)); -+ if (!data->state.base_headers) -+ result = CURLE_OUT_OF_MEMORY; -+ break; -+ - #ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXYHEADER: - /* -@@ -2398,6 +2416,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - result = Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], - va_arg(param, char *)); - break; -+ -+ case CURLOPT_SSL_SIG_HASH_ALGS: -+ /* -+ * Set the list of hash algorithms we want to use in the SSL connection. -+ * Specify comma-delimited list of algorithms to use. -+ */ -+ result = Curl_setstropt(&data->set.str[STRING_SSL_SIG_HASH_ALGS], -+ va_arg(param, char *)); -+ break; -+ -+ case CURLOPT_SSL_CERT_COMPRESSION: -+ /* -+ * Set the list of ceritifcate compression algorithms we support in the TLS -+ * connection. -+ * Specify comma-delimited list of algorithms to use. Options are "zlib" -+ * and "brotli". -+ */ -+ result = Curl_setstropt(&data->set.str[STRING_SSL_CERT_COMPRESSION], -+ va_arg(param, char *)); -+ break; -+ - #endif - case CURLOPT_IPRESOLVE: - arg = va_arg(param, long); -@@ -2936,6 +2975,52 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - case CURLOPT_SSL_ENABLE_ALPN: - data->set.ssl_enable_alpn = (0 != va_arg(param, long)); - break; -+ case CURLOPT_SSL_ENABLE_ALPS: -+ data->set.ssl_enable_alps = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_SSL_ENABLE_TICKET: -+ data->set.ssl_enable_ticket = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_SSL_PERMUTE_EXTENSIONS: -+ data->set.ssl_permute_extensions = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_TLS_GREASE: -+ data->set.tls_grease = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_TLS_EXTENSION_ORDER: -+ result = Curl_setstropt(&data->set.str[STRING_TLS_EXTENSION_ORDER], -+ va_arg(param, char *)); -+ break; -+ case CURLOPT_TLS_KEY_USAGE_NO_CHECK: -+ data->set.tls_key_usage_no_check = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS: -+ data->set.tls_signed_cert_timestamps = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ case CURLOPT_TLS_STATUS_REQUEST: -+ data->set.tls_status_request = (0 != va_arg(param, long)) ? TRUE : FALSE; -+ break; -+ -+#ifdef USE_HTTP2 -+ case CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER: -+ result = Curl_setstropt(&data->set.str[STRING_HTTP2_PSEUDO_HEADERS_ORDER], -+ va_arg(param, char *)); -+ break; -+ case CURLOPT_HTTP2_SETTINGS: -+ result = Curl_setstropt(&data->set.str[STRING_HTTP2_SETTINGS], -+ va_arg(param, char *)); -+ break; -+ case CURLOPT_HTTP2_WINDOW_UPDATE: -+ arg = va_arg(param, long); -+ if(arg < -1) -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ data->set.http2_window_update = arg; -+ break; -+ case CURLOPT_HTTP2_STREAMS: -+ result = Curl_setstropt(&data->set.str[STRING_HTTP2_STREAMS], -+ va_arg(param, char *)); -+ break; -+#endif - #ifdef USE_UNIX_SOCKETS - case CURLOPT_UNIX_SOCKET_PATH: - data->set.abstract_unix_socket = FALSE; -@@ -2963,6 +3048,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - break; - #else - return CURLE_NOT_BUILT_IN; -+#endif -+ case CURLOPT_STREAM_EXCLUSIVE: -+#if defined(USE_HTTP2) || defined(USE_HTTP3) -+ arg = va_arg(param, long); -+ data->set.priority.exclusive = (int)arg; -+ break; -+#else -+ return CURLE_NOT_BUILT_IN; - #endif - case CURLOPT_STREAM_DEPENDS: - case CURLOPT_STREAM_DEPENDS_E: -@@ -3132,6 +3225,31 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) - data->set.ws_raw_mode = raw; - break; - } -+#endif -+#ifdef USE_ECH -+ case CURLOPT_ECH: { -+ size_t plen = 0; -+ argptr = va_arg(param, char *); -+ if(!argptr) { -+ data->set.tls_ech = CURLECH_DISABLE; -+ result = CURLE_BAD_FUNCTION_ARGUMENT; -+ return result; -+ } -+ plen = strlen(argptr); -+ if(plen > CURL_MAX_INPUT_LENGTH) { -+ data->set.tls_ech = CURLECH_DISABLE; -+ result = CURLE_BAD_FUNCTION_ARGUMENT; -+ return result; -+ } -+ if(plen == 6 && strcasecompare(argptr, "GREASE")) -+ data->set.tls_ech = CURLECH_GREASE; -+ else { -+ data->set.tls_ech = CURLECH_DISABLE; -+ result = CURLE_BAD_FUNCTION_ARGUMENT; -+ return result; -+ } -+ break; -+ } - #endif - case CURLOPT_QUICK_EXIT: - data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L; -diff --git a/lib/strerror.c b/lib/strerror.c -index a900e78d1..e7d54905a 100644 ---- a/lib/strerror.c -+++ b/lib/strerror.c -@@ -322,6 +322,11 @@ curl_easy_strerror(CURLcode error) - case CURLE_TOO_LARGE: - return "A value or data field grew larger than allowed"; - -+#ifdef USE_ECH -+ case CURLE_ECH_REQUIRED: -+ return "ECH attempted but failed"; -+#endif -+ - /* error codes not used by current libcurl */ - case CURLE_OBSOLETE20: - case CURLE_OBSOLETE24: -diff --git a/lib/transfer.c b/lib/transfer.c -index e31d1d6db..66e106901 100644 ---- a/lib/transfer.c -+++ b/lib/transfer.c -@@ -105,7 +105,15 @@ char *Curl_checkheaders(const struct Curl_easy *data, - DEBUGASSERT(thislen); - DEBUGASSERT(thisheader[thislen-1] != ':'); - -- for(head = data->set.headers; head; head = head->next) { -+ /* -+ * curl-impersonate: -+ * Check if we have overriden the user-supplied list of headers. -+ */ -+ head = data->set.headers; -+ if (data->state.merged_headers) -+ head = data->state.merged_headers; -+ -+ for(; head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen) && - Curl_headersep(head->data[thislen]) ) - return head->data; -diff --git a/lib/url.c b/lib/url.c -index 224b9f3e2..db07bfa40 100644 ---- a/lib/url.c -+++ b/lib/url.c -@@ -320,6 +320,20 @@ CURLcode Curl_close(struct Curl_easy **datap) - Curl_safefree(data->state.aptr.proxyuser); - Curl_safefree(data->state.aptr.proxypasswd); - -+ /* curl-impersonate: Free the list set by CURLOPT_HTTPBASEHEADER. */ -+ curl_slist_free_all(data->state.base_headers); -+ /* curl-impersonate: Free the dynamic list of headers. */ -+ curl_slist_free_all(data->state.merged_headers); -+ -+#ifndef CURL_DISABLE_DOH -+ if(data->req.doh) { -+ Curl_dyn_free(&data->req.doh->probe[0].serverdoh); -+ Curl_dyn_free(&data->req.doh->probe[1].serverdoh); -+ curl_slist_free_all(data->req.doh->headers); -+ Curl_safefree(data->req.doh); -+ } -+#endif -+ - #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API) - Curl_mime_cleanpart(data->state.formp); - Curl_safefree(data->state.formp); -@@ -458,6 +472,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) - set->tcp_fastopen = FALSE; - set->tcp_nodelay = TRUE; - set->ssl_enable_alpn = TRUE; -+ set->ssl_enable_ticket = TRUE; -+ set->tls_grease = TRUE; - set->expect_100_timeout = 1000L; /* Wait for a second by default. */ - set->sep_headers = TRUE; /* separated header lists by default */ - set->buffer_size = READBUFFER_SIZE; -@@ -3664,6 +3680,11 @@ static CURLcode create_conn(struct Curl_easy *data, - (default) */ - if(data->set.ssl_enable_alpn) - conn->bits.tls_enable_alpn = TRUE; -+ -+ /* curl-impersonate: Turn on ALPS if ALPN is enabled and the bit is -+ * enabled. */ -+ if(data->set.ssl_enable_alps) -+ conn->bits.tls_enable_alps = TRUE; - } - - if(waitpipe) -diff --git a/lib/urldata.h b/lib/urldata.h -index ce28f25bb..c61641d5a 100644 ---- a/lib/urldata.h -+++ b/lib/urldata.h -@@ -53,6 +53,15 @@ - #define PORT_GOPHER 70 - #define PORT_MQTT 1883 - -+#ifdef USE_ECH -+/* CURLECH_ defines are for the tls_ech option */ -+# define CURLECH_DISABLE 0 -+# define CURLECH_GREASE 1 -+# define CURLECH_ENABLE 2 -+# define CURLECH_HARD 3 -+# define CURLECH_CLA_CFG 4 -+#endif -+ - struct curl_trc_featt; - - #ifdef USE_WEBSOCKETS -@@ -298,6 +307,8 @@ struct ssl_primary_config { - char *password; /* TLS password (for, e.g., SRP) */ - #endif - char *curves; /* list of curves to use */ -+ char *sig_hash_algs; /* List of signature hash algorithms to use */ -+ char *cert_compression; /* List of certificate compression algorithms. */ - unsigned char ssl_options; /* the CURLOPT_SSL_OPTIONS bitmask */ - unsigned int version_max; /* max supported version the client wants to use */ - unsigned char version; /* what version the client wants to use */ -@@ -305,6 +316,7 @@ struct ssl_primary_config { - BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */ - BIT(verifystatus); /* set TRUE if certificate status must be checked */ - BIT(sessionid); /* cache session IDs or not */ -+ // BIT(grease); /* grease enabled? */ - }; - - struct ssl_config_data { -@@ -545,6 +557,10 @@ struct ConnectBits { - BIT(multiplex); /* connection is multiplexed */ - BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(tls_enable_alpn); /* TLS ALPN extension? */ -+ BIT(tls_enable_alps); /* TLS ALPS extension? */ -+ BIT(tls_enable_ticket); /* TLS session ticket extension? */ -+ BIT(tls_permute_extensions); /* TLS extension permutations */ -+ BIT(tls_grease); /* TLS grease? */ - #ifndef CURL_DISABLE_DOH - BIT(doh); - #endif -@@ -1320,6 +1336,19 @@ struct UrlState { - CURLcode hresult; /* used to pass return codes back from hyper callbacks */ - #endif - -+ /* -+ * curl-impersonate: -+ * List of "base" headers set by CURLOPT_HTTPBASEHEADER. -+ */ -+ struct curl_slist *base_headers; -+ /* -+ * curl-impersonate: -+ * Dynamically-constructed list of HTTP headers. -+ * This list is a merge of the default HTTP headers needed to impersonate a -+ * browser, together with any user-supplied headers. -+ */ -+ struct curl_slist *merged_headers; -+ - #ifndef CURL_DISABLE_VERBOSE_STRINGS - struct curl_trc_feat *feat; /* opt. trace feature transfer is part of */ - #endif -@@ -1496,6 +1525,14 @@ enum dupstring { - STRING_SSL_EC_CURVES, - STRING_AWS_SIGV4, /* Parameters for V4 signature */ - STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */ -+ STRING_SSL_SIG_HASH_ALGS, -+ STRING_SSL_CERT_COMPRESSION, -+ STRING_HTTP2_PSEUDO_HEADERS_ORDER, -+ STRING_HTTP2_SETTINGS, -+ STRING_HTTP2_STREAMS, -+ STRING_ECH_CONFIG, /* CURLOPT_ECH_CONFIG */ -+ STRING_ECH_PUBLIC, /* CURLOPT_ECH_PUBLIC */ -+ STRING_TLS_EXTENSION_ORDER, - - /* -- end of null-terminated strings -- */ - -@@ -1791,6 +1828,13 @@ struct UserDefined { - BIT(tcp_keepalive); /* use TCP keepalives */ - BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(ssl_enable_alpn);/* TLS ALPN extension? */ -+ BIT(ssl_enable_alps);/* TLS ALPS extension? */ -+ BIT(ssl_enable_ticket); /* TLS session ticket extension */ -+ BIT(ssl_permute_extensions); /* TLS Permute extensions */ -+ BIT(tls_grease); /* TLS grease? */ -+ BIT(tls_key_usage_no_check); /* TLS key_usage_check? */ -+ BIT(tls_signed_cert_timestamps); /* TLS signed cert timestamps? */ -+ BIT(tls_status_request); /* TLS status request */ - BIT(path_as_is); /* allow dotdots? */ - BIT(pipewait); /* wait for multiplex status before starting a new - connection */ -@@ -1811,6 +1855,10 @@ struct UserDefined { - #ifdef USE_WEBSOCKETS - BIT(ws_raw_mode); - #endif -+#ifdef USE_ECH -+ int tls_ech; /* TLS ECH configuration */ -+#endif -+ int http2_window_update; - }; - - #ifndef CURL_DISABLE_MIME -diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c -index a3953f6c3..a3421e2bb 100644 ---- a/lib/vtls/openssl.c -+++ b/lib/vtls/openssl.c -@@ -79,9 +79,24 @@ - #include - #include - #include -+#include - #include - #include - -+#ifdef HAVE_LIBZ -+#include -+#endif -+#ifdef HAVE_BROTLI -+#include -+#endif -+ -+#ifdef USE_ECH -+# ifndef OPENSSL_IS_BORINGSSL -+# include -+# endif -+# include "curl_base64.h" -+#endif /* USE_ECH */ -+ - #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) - #include - #endif -@@ -276,6 +291,113 @@ - #define HAVE_OPENSSL_VERSION - #endif - -+#if defined(OPENSSL_IS_BORINGSSL) -+#define HAVE_SSL_CTX_SET_VERIFY_ALGORITHM_PREFS -+ -+/* -+ * kMaxSignatureAlgorithmNameLen and kSignatureAlgorithmNames -+ * Taken from BoringSSL, see ssl/ssl_privkey.cc -+ * */ -+static const size_t kMaxSignatureAlgorithmNameLen = 23; -+ -+static const struct { -+ uint16_t signature_algorithm; -+ const char *name; -+} kSignatureAlgorithmNames[] = { -+ {SSL_SIGN_RSA_PKCS1_MD5_SHA1, "rsa_pkcs1_md5_sha1"}, -+ {SSL_SIGN_RSA_PKCS1_SHA1, "rsa_pkcs1_sha1"}, -+ {SSL_SIGN_RSA_PKCS1_SHA256, "rsa_pkcs1_sha256"}, -+ {SSL_SIGN_RSA_PKCS1_SHA384, "rsa_pkcs1_sha384"}, -+ {SSL_SIGN_RSA_PKCS1_SHA512, "rsa_pkcs1_sha512"}, -+ {SSL_SIGN_ECDSA_SHA1, "ecdsa_sha1"}, -+ {SSL_SIGN_ECDSA_SECP256R1_SHA256, "ecdsa_secp256r1_sha256"}, -+ {SSL_SIGN_ECDSA_SECP384R1_SHA384, "ecdsa_secp384r1_sha384"}, -+ {SSL_SIGN_ECDSA_SECP521R1_SHA512, "ecdsa_secp521r1_sha512"}, -+ {SSL_SIGN_RSA_PSS_RSAE_SHA256, "rsa_pss_rsae_sha256"}, -+ {SSL_SIGN_RSA_PSS_RSAE_SHA384, "rsa_pss_rsae_sha384"}, -+ {SSL_SIGN_RSA_PSS_RSAE_SHA512, "rsa_pss_rsae_sha512"}, -+ {SSL_SIGN_ED25519, "ed25519"}, -+}; -+ -+#define MAX_SIG_ALGS \ -+ sizeof(kSignatureAlgorithmNames) / sizeof(kSignatureAlgorithmNames[0]) -+ -+/* Default signature hash algorithms taken from Chrome/Chromium. -+ * See kVerifyPeers @ net/socket/ssl_client_socket_impl.cc */ -+static const uint16_t default_sig_algs[] = { -+ SSL_SIGN_ECDSA_SECP256R1_SHA256, SSL_SIGN_RSA_PSS_RSAE_SHA256, -+ SSL_SIGN_RSA_PKCS1_SHA256, SSL_SIGN_ECDSA_SECP384R1_SHA384, -+ SSL_SIGN_RSA_PSS_RSAE_SHA384, SSL_SIGN_RSA_PKCS1_SHA384, -+ SSL_SIGN_RSA_PSS_RSAE_SHA512, SSL_SIGN_RSA_PKCS1_SHA512, -+}; -+ -+#define DEFAULT_SIG_ALGS_LENGTH \ -+ sizeof(default_sig_algs) / sizeof(default_sig_algs[0]) -+ -+static CURLcode parse_sig_algs(struct Curl_easy *data, -+ const char *sigalgs, -+ uint16_t *algs, -+ size_t *nalgs) -+{ -+ *nalgs = 0; -+ while (sigalgs && sigalgs[0]) { -+ int i; -+ bool found = FALSE; -+ const char *end; -+ size_t len; -+ char algname[kMaxSignatureAlgorithmNameLen + 1]; -+ -+ end = strpbrk(sigalgs, ":,"); -+ if (end) -+ len = end - sigalgs; -+ else -+ len = strlen(sigalgs); -+ -+ if (len > kMaxSignatureAlgorithmNameLen) { -+ failf(data, "Bad signature hash algorithm list"); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ -+ if (!len) { -+ ++sigalgs; -+ continue; -+ } -+ -+ if (*nalgs == MAX_SIG_ALGS) { -+ /* Reached the maximum number of possible algorithms, but more data -+ * available in the list. */ -+ failf(data, "Bad signature hash algorithm list"); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ -+ memcpy(algname, sigalgs, len); -+ algname[len] = 0; -+ -+ for (i = 0; i < MAX_SIG_ALGS; i++) { -+ if (strcasecompare(algname, kSignatureAlgorithmNames[i].name)) { -+ algs[*nalgs] = kSignatureAlgorithmNames[i].signature_algorithm; -+ (*nalgs)++; -+ found = TRUE; -+ break; -+ } -+ } -+ -+ if (!found) { -+ failf(data, "Unknown signature hash algorithm: '%s'", algname); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ -+ if (end) -+ sigalgs = ++end; -+ else -+ break; -+ } -+ -+ return CURLE_OK; -+} -+ -+#endif -+ - #if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) - typedef uint32_t sslerr_t; - #else -@@ -2644,6 +2766,151 @@ static const char *tls_rt_type(int type) - } - } - -+#ifdef HAVE_LIBZ -+int DecompressZlibCert(SSL *ssl, -+ CRYPTO_BUFFER** out, -+ size_t uncompressed_len, -+ const uint8_t* in, -+ size_t in_len) -+{ -+ z_stream strm; -+ uint8_t* data; -+ CRYPTO_BUFFER* decompressed = CRYPTO_BUFFER_alloc(&data, uncompressed_len); -+ if(!decompressed) { -+ return 0; -+ } -+ -+ strm.zalloc = NULL; -+ strm.zfree = NULL; -+ strm.opaque = NULL; -+ strm.next_in = (Bytef *)in; -+ strm.avail_in = in_len; -+ strm.next_out = (Bytef *)data; -+ strm.avail_out = uncompressed_len; -+ -+ if(inflateInit(&strm) != Z_OK) { -+ CRYPTO_BUFFER_free(decompressed); -+ return 0; -+ } -+ -+ if(inflate(&strm, Z_FINISH) != Z_STREAM_END || -+ strm.avail_in != 0 || -+ strm.avail_out != 0) { -+ inflateEnd(&strm); -+ CRYPTO_BUFFER_free(decompressed); -+ return 0; -+ } -+ -+ inflateEnd(&strm); -+ *out = decompressed; -+ return 1; -+} -+#endif -+ -+#ifdef HAVE_BROTLI -+ -+/* Taken from Chromium and adapted to C, -+ * see net/ssl/cert_compression.cc -+ */ -+int DecompressBrotliCert(SSL* ssl, -+ CRYPTO_BUFFER** out, -+ size_t uncompressed_len, -+ const uint8_t* in, -+ size_t in_len) { -+ uint8_t* data; -+ CRYPTO_BUFFER* decompressed = CRYPTO_BUFFER_alloc(&data, uncompressed_len); -+ if (!decompressed) { -+ return 0; -+ } -+ -+ size_t output_size = uncompressed_len; -+ if (BrotliDecoderDecompress(in_len, in, &output_size, data) != -+ BROTLI_DECODER_RESULT_SUCCESS || -+ output_size != uncompressed_len) { -+ CRYPTO_BUFFER_free(decompressed); -+ return 0; -+ } -+ -+ *out = decompressed; -+ return 1; -+} -+#endif -+ -+#if defined(HAVE_LIBZ) || defined(HAVE_BROTLI) -+static struct { -+ char *alg_name; -+ uint16_t alg_id; -+ ssl_cert_compression_func_t compress; -+ ssl_cert_decompression_func_t decompress; -+} cert_compress_algs[] = { -+#ifdef HAVE_LIBZ -+ {"zlib", TLSEXT_cert_compression_zlib, NULL, DecompressZlibCert}, -+#endif -+#ifdef HAVE_BROTLI -+ {"brotli", TLSEXT_cert_compression_brotli, NULL, DecompressBrotliCert}, -+#endif -+}; -+ -+#define NUM_CERT_COMPRESSION_ALGS \ -+ sizeof(cert_compress_algs) / sizeof(cert_compress_algs[0]) -+ -+/* -+ * curl-impersonate: -+ * Add support for TLS extension 27 - compress_certificate. -+ * This calls the BoringSSL-specific API SSL_CTX_add_cert_compression_alg -+ * for each algorithm specified in cert_compression, which is a comma separated list. -+ */ -+static CURLcode add_cert_compression(struct Curl_easy *data, -+ SSL_CTX *ctx, -+ const char *algorithms) -+{ -+ int i; -+ const char *s = algorithms; -+ char *alg_name; -+ size_t alg_name_len; -+ bool found; -+ -+ while (s && s[0]) { -+ found = FALSE; -+ -+ for(i = 0; i < NUM_CERT_COMPRESSION_ALGS; i++) { -+ alg_name = cert_compress_algs[i].alg_name; -+ alg_name_len = strlen(alg_name); -+ if(strlen(s) >= alg_name_len && -+ strncasecompare(s, alg_name, alg_name_len) && -+ (s[alg_name_len] == ',' || s[alg_name_len] == 0)) { -+ if(!SSL_CTX_add_cert_compression_alg(ctx, -+ cert_compress_algs[i].alg_id, -+ cert_compress_algs[i].compress, -+ cert_compress_algs[i].decompress)) { -+ failf(data, "Error adding certificate compression algorithm '%s'", -+ alg_name); -+ return CURLE_SSL_CIPHER; -+ } -+ s += alg_name_len; -+ if(*s == ',') -+ s += 1; -+ found = TRUE; -+ break; -+ } -+ } -+ -+ if(!found) { -+ failf(data, "Invalid compression algorithm list"); -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+ } -+ } -+ -+ return CURLE_OK; -+} -+#else -+static CURLcode add_cert_compression(SSL_CTX *ctx, const char *algorithms) -+{ -+ /* No compression algorithms are available. */ -+ return CURLE_BAD_FUNCTION_ARGUMENT; -+} -+#endif -+ - /* - * Our callback from the SSL/TLS layers. - */ -@@ -3616,7 +3883,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - ctx_options = SSL_OP_ALL; - - #ifdef SSL_OP_NO_TICKET -- ctx_options |= SSL_OP_NO_TICKET; -+ if(data->set.ssl_enable_ticket) { -+ /* curl-impersonate: -+ * Turn off SSL_OP_NO_TICKET, we want TLS extension 35 (session_ticket) -+ * to be present in the client hello. */ -+ ctx_options &= ~SSL_OP_NO_TICKET; -+ } else { -+ ctx_options |= SSL_OP_NO_TICKET; -+ } - #endif - - #ifdef SSL_OP_NO_COMPRESSION -@@ -3683,6 +3957,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - } - #endif - -+ SSL_CTX_set_options(backend->ctx, -+ SSL_OP_LEGACY_SERVER_CONNECT); -+ SSL_CTX_set_mode(backend->ctx, -+ SSL_MODE_CBC_RECORD_SPLITTING | SSL_MODE_ENABLE_FALSE_START); -+ -+ /* curl-impersonate: Enable TLS extensions 18 - signed_certificate_timestamp. */ -+ if(data->set.tls_signed_cert_timestamps) { -+ SSL_CTX_enable_signed_cert_timestamps(backend->ctx); -+ } -+ -+ /* curl-impersonate: Enable TLS extensions 5 - status_request */ -+ if(data->set.tls_status_request) { -+ SSL_CTX_enable_ocsp_stapling(backend->ctx); -+ } -+ - if(ssl_cert || ssl_cert_blob || ssl_cert_type) { - if(!result && - !cert_stuff(data, backend->ctx, -@@ -3736,6 +4025,35 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - } - #endif - -+#ifdef HAVE_SSL_CTX_SET_VERIFY_ALGORITHM_PREFS -+ { -+ uint16_t algs[MAX_SIG_ALGS]; -+ size_t nalgs; -+ /* curl-impersonate: Set the signature algorithms (TLS extension 13). -+ * See net/socket/ssl_client_socket_impl.cc in Chromium's source. */ -+ char *sig_hash_algs = conn_config->sig_hash_algs; -+ if (sig_hash_algs) { -+ CURLcode result = parse_sig_algs(data, sig_hash_algs, algs, &nalgs); -+ if (result) -+ return result; -+ if (!SSL_CTX_set_verify_algorithm_prefs(backend->ctx, algs, nalgs)) { -+ failf(data, "failed setting signature hash algorithms list: '%s'", -+ sig_hash_algs); -+ return CURLE_SSL_CIPHER; -+ } -+ } else { -+ /* Use defaults from Chrome. */ -+ if (!SSL_CTX_set_verify_algorithm_prefs(backend->ctx, -+ default_sig_algs, -+ DEFAULT_SIG_ALGS_LENGTH)) { -+ failf(data, "failed setting signature hash algorithms list: '%s'", -+ sig_hash_algs); -+ return CURLE_SSL_CIPHER; -+ } -+ } -+ } -+#endif -+ - #ifdef USE_OPENSSL_SRP - if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { - char * const ssl_username = ssl_config->primary.username; -@@ -3761,6 +4079,44 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - } - #endif - -+ /* curl-impersonate: -+ * Configure BoringSSL to behave like Chrome. -+ * See Constructor of SSLContext at net/socket/ssl_client_socket_impl.cc -+ * and SSLClientSocketImpl::Init() -+ * in the Chromium's source code. */ -+ -+ /* curl-impersonate: Enable TLS GREASE. */ -+ if(data->set.tls_grease) { -+ SSL_CTX_set_grease_enabled(backend->ctx, 1); -+ } -+ -+ /* -+ * curl-impersonate: Enable TLS extension permutation, enabled by default -+ * since Chrome 110. -+ */ -+ if(data->set.ssl_permute_extensions) { -+ SSL_CTX_set_permute_extensions(backend->ctx, 1); -+ } -+ -+ /* curl-impersonate: Set TLS extensions order. */ -+ if(data->set.str[STRING_TLS_EXTENSION_ORDER]) { -+ SSL_CTX_set_extension_order(backend->ctx, data->set.str[STRING_TLS_EXTENSION_ORDER]); -+ } -+ -+ // curl-impersonate: Set key usage check -+ if(data->set.tls_key_usage_no_check) { -+ SSL_CTX_set_key_usage_check_enabled(backend->ctx, 0); -+ }else{ -+ SSL_CTX_set_key_usage_check_enabled(backend->ctx, 1); -+ } -+ -+ if(conn_config->cert_compression && -+ add_cert_compression(data, -+ backend->ctx, -+ conn_config->cert_compression)) -+ return CURLE_SSL_CIPHER; -+ -+ - /* OpenSSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with -@@ -3816,6 +4172,24 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - - SSL_set_app_data(backend->handle, cf); - -+#ifdef HAS_ALPN -+ if(connssl->alps) { -+ size_t i; -+ struct alpn_proto_buf proto; -+ -+ for(i = 0; i < connssl->alps->count; ++i) { -+ /* curl-impersonate: Add the ALPS extension (17513) like Chrome does. */ -+ // XXX: Firefox does not enable this. -+ SSL_add_application_settings(backend->handle, connssl->alps->entries[i], -+ strlen(connssl->alps->entries[i]), NULL, -+ 0); -+ } -+ -+ Curl_alpn_to_proto_str(&proto, connssl->alps); -+ infof(data, VTLS_INFOF_ALPS_OFFER_1STR, proto.data); -+ } -+#endif -+ - #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ - !defined(OPENSSL_NO_OCSP) - if(conn_config->verifystatus) -@@ -3839,6 +4213,21 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, - } - #endif - -+#ifdef USE_ECH -+ if(data->set.tls_ech != CURLECH_DISABLE) { -+ unsigned char *ech_config = NULL; -+ size_t ech_config_len = 0; -+ int trying_ech_now = 0; -+ if(data->set.tls_ech == CURLECH_GREASE) { -+# ifdef OPENSSL_IS_BORINGSSL -+ SSL_set_enable_ech_grease(backend->handle, 1); -+# else -+ SSL_set_options(backend->handle, SSL_OP_ECH_GREASE); -+# endif -+ } -+ } -+#endif -+ - SSL_set_app_data(backend->handle, cf); - - connssl->reused_session = FALSE; -@@ -4050,6 +4439,60 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, - negotiated_group_name? negotiated_group_name : "[blank]", - OBJ_nid2sn(psigtype_nid)); - -+#ifdef USE_ECH -+# ifndef OPENSSL_IS_BORINGSSL -+ if(data->set.tls_ech != CURLECH_DISABLE) { -+ char *inner = NULL, *outer = NULL; -+ const char *status = NULL; -+ int rv; -+ -+ rv = SSL_ech_get_status(backend->handle, &inner, &outer); -+ switch(rv) { -+ case SSL_ECH_STATUS_SUCCESS: -+ status = "Succeeded"; -+ break; -+ case SSL_ECH_STATUS_GREASE_ECH: -+ status = "sent GREASE, got retry-configs"; -+ break; -+ case SSL_ECH_STATUS_GREASE: -+ status = "sent GREASE"; -+ break; -+ case SSL_ECH_STATUS_NOT_TRIED: -+ status = "not attempted"; -+ break; -+ case SSL_ECH_STATUS_NOT_CONFIGURED: -+ status = "not configured"; -+ break; -+ case SSL_ECH_STATUS_BACKEND: -+ status = "backend (unexpected)"; -+ break; -+ case SSL_ECH_STATUS_FAILED: -+ status = "failed"; -+ break; -+ case SSL_ECH_STATUS_BAD_CALL: -+ status = "bad call (unexpected)"; -+ break; -+ case SSL_ECH_STATUS_BAD_NAME: -+ status = "bad name (unexpected)"; -+ break; -+ default: -+ status = "unexpected status"; -+ infof(data, "ECH: unexpected status %d",rv); -+ } -+ infof(data, "ECH: result: status is %s, inner is %s, outer is %s", -+ (status?status:"NULL"), -+ (inner?inner:"NULL"), -+ (outer?outer:"NULL")); -+ OPENSSL_free(inner); -+ OPENSSL_free(outer); -+ if(rv != SSL_ECH_STATUS_SUCCESS && data->set.tls_ech == CURLECH_HARD) { -+ infof(data, "ECH: ech-hard failed"); -+ return CURLE_SSL_CONNECT_ERROR; -+ } -+ } -+# endif /* BORING */ -+#endif /* USE_ECH */ -+ - #ifdef HAS_ALPN - /* Sets data and len to negotiated protocol, len is 0 if no protocol was - * negotiated -diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c -index d13a3cb1b..5ec3db492 100644 ---- a/lib/vtls/vtls.c -+++ b/lib/vtls/vtls.c -@@ -139,6 +139,9 @@ static const struct alpn_spec ALPN_SPEC_H11 = { - static const struct alpn_spec ALPN_SPEC_H2_H11 = { - { ALPN_H2, ALPN_HTTP_1_1 }, 2 - }; -+static const struct alpn_spec ALPN_SPEC_H2 = { -+ { ALPN_H2 }, 1 -+}; - #endif - - static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) -@@ -155,6 +158,17 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn) - Avoid "http/1.0" because some servers don't support it. */ - return &ALPN_SPEC_H11; - } -+ -+static const struct alpn_spec *alps_get_spec(int httpwant, bool use_alps) -+{ -+ if(!use_alps) -+ return NULL; -+#ifdef USE_HTTP2 -+ if(httpwant >= CURL_HTTP_VERSION_2) -+ return &ALPN_SPEC_H2; -+#endif -+ return NULL; -+} - #endif /* USE_SSL */ - - -@@ -198,6 +212,8 @@ match_ssl_primary_config(struct Curl_easy *data, - strcasecompare(c1->cipher_list, c2->cipher_list) && - strcasecompare(c1->cipher_list13, c2->cipher_list13) && - strcasecompare(c1->curves, c2->curves) && -+ strcasecompare(c1->sig_hash_algs, c2->sig_hash_algs) && -+ strcasecompare(c1->cert_compression, c2->cert_compression) && - strcasecompare(c1->CRLfile, c2->CRLfile) && - strcasecompare(c1->pinned_key, c2->pinned_key)) - return TRUE; -@@ -242,6 +258,8 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source, - CLONE_STRING(cipher_list13); - CLONE_STRING(pinned_key); - CLONE_STRING(curves); -+ CLONE_STRING(sig_hash_algs); -+ CLONE_STRING(cert_compression); - CLONE_STRING(CRLfile); - #ifdef USE_TLS_SRP - CLONE_STRING(username); -@@ -264,6 +282,8 @@ static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) - Curl_safefree(sslc->ca_info_blob); - Curl_safefree(sslc->issuercert_blob); - Curl_safefree(sslc->curves); -+ Curl_safefree(sslc->sig_hash_algs); -+ Curl_safefree(sslc->cert_compression); - Curl_safefree(sslc->CRLfile); - #ifdef USE_TLS_SRP - Curl_safefree(sslc->username); -@@ -287,6 +307,8 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data) - data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT]; - data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO]; - data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES]; -+ data->set.ssl.primary.sig_hash_algs = data->set.str[STRING_SSL_SIG_HASH_ALGS]; -+ data->set.ssl.primary.cert_compression = data->set.str[STRING_SSL_CERT_COMPRESSION]; - #ifdef USE_TLS_SRP - data->set.ssl.primary.username = data->set.str[STRING_TLSAUTH_USERNAME]; - data->set.ssl.primary.password = data->set.str[STRING_TLSAUTH_PASSWORD]; -@@ -453,7 +475,8 @@ static bool ssl_prefs_check(struct Curl_easy *data) - } - - static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, -- const struct alpn_spec *alpn) -+ const struct alpn_spec *alpn, -+ const struct alpn_spec *alps) - { - struct ssl_connect_data *ctx; - -@@ -463,6 +486,7 @@ static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data, - return NULL; - - ctx->alpn = alpn; -+ ctx->alps = alps; - ctx->backend = calloc(1, Curl_ssl->sizeof_ssl_backend_data); - if(!ctx->backend) { - free(ctx); -@@ -1885,8 +1909,11 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, - - DEBUGASSERT(data->conn); - -- ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant, -- conn->bits.tls_enable_alpn)); -+ ctx = cf_ctx_new(data, -+ alpn_get_spec(data->state.httpwant, -+ conn->bits.tls_enable_alpn), -+ alps_get_spec(data->state.httpwant, -+ conn->bits.tls_enable_alps)); - if(!ctx) { - result = CURLE_OUT_OF_MEMORY; - goto out; -@@ -1936,6 +1963,7 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, - struct ssl_connect_data *ctx; - CURLcode result; - bool use_alpn = conn->bits.tls_enable_alpn; -+ bool use_alps = conn->bits.tls_enable_alps; - int httpwant = CURL_HTTP_VERSION_1_1; - - #ifdef USE_HTTP2 -@@ -1945,7 +1973,8 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, - } - #endif - -- ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn)); -+ ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn), -+ alps_get_spec(httpwant, use_alps)); - if(!ctx) { - result = CURLE_OUT_OF_MEMORY; - goto out; -diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h -index 744bbf8fd..3bd42ee9d 100644 ---- a/lib/vtls/vtls.h -+++ b/lib/vtls/vtls.h -@@ -44,6 +44,8 @@ struct Curl_ssl_session; - "ALPN: server did not agree on a protocol. Uses default." - #define VTLS_INFOF_ALPN_OFFER_1STR \ - "ALPN: curl offers %s" -+#define VTLS_INFOF_ALPS_OFFER_1STR \ -+ "ALPS: offers %s" - #define VTLS_INFOF_ALPN_ACCEPTED_1STR \ - ALPN_ACCEPTED "%s" - #define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR \ -diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h -index 0361fa95a..417e6a689 100644 ---- a/lib/vtls/vtls_int.h -+++ b/lib/vtls/vtls_int.h -@@ -70,6 +70,7 @@ struct ssl_connect_data { - ssl_connect_state connecting_state; - struct ssl_peer peer; - const struct alpn_spec *alpn; /* ALPN to use or NULL for none */ -+ const struct alpn_spec *alps; /* ALPS to use or NULL for none */ - void *backend; /* vtls backend specific props */ - struct cf_call_data call_data; /* data handle used in current call */ - struct curltime handshake_done; /* time when handshake finished */ -diff --git a/libcurl.def b/libcurl.def -index c6c96063a..ac52a596d 100644 ---- a/libcurl.def -+++ b/libcurl.def -@@ -5,6 +5,7 @@ curl_easy_escape - curl_easy_getinfo - curl_easy_header - curl_easy_init -+curl_easy_impersonate - curl_easy_nextheader - curl_easy_option_by_id - curl_easy_option_by_name -diff --git a/libcurl.pc.in b/libcurl.pc.in -index 9db6b0f89..14c2f23e0 100644 ---- a/libcurl.pc.in -+++ b/libcurl.pc.in -@@ -36,6 +36,6 @@ Name: libcurl - URL: https://curl.se/ - Description: Library to transfer files with ftp, http, etc. - Version: @CURLVERSION@ --Libs: -L${libdir} -lcurl @LIBCURL_NO_SHARED@ -+Libs: -L${libdir} -lcurl-impersonate-chrome @LIBCURL_NO_SHARED@ - Libs.private: @LIBCURL_LIBS@ - Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@ -diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 -index 9a4547709..42bc87373 100644 ---- a/m4/curl-compilers.m4 -+++ b/m4/curl-compilers.m4 -@@ -381,42 +381,55 @@ AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ - AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl - AC_REQUIRE([CURL_CHECK_COMPILER])dnl - AC_MSG_CHECKING([convert -I options to -isystem]) -- if test "$compiler_id" = "GNU_C" || -- test "$compiler_id" = "CLANG"; then -- AC_MSG_RESULT([yes]) -- tmp_has_include="no" -- tmp_chg_FLAGS="$CFLAGS" -- for word1 in $tmp_chg_FLAGS; do -- case "$word1" in -- -I*) -- tmp_has_include="yes" -- ;; -- esac -- done -- if test "$tmp_has_include" = "yes"; then -- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` -- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` -- CFLAGS="$tmp_chg_FLAGS" -- squeeze CFLAGS -- fi -- tmp_has_include="no" -- tmp_chg_FLAGS="$CPPFLAGS" -- for word1 in $tmp_chg_FLAGS; do -- case "$word1" in -- -I*) -- tmp_has_include="yes" -- ;; -- esac -- done -- if test "$tmp_has_include" = "yes"; then -- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` -- tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` -- CPPFLAGS="$tmp_chg_FLAGS" -- squeeze CPPFLAGS -- fi -- else -+ case $host_os in -+ darwin*) -+ dnl curl-impersonate: On macos, clang gives priority to /usr/local/include -+ dnl over locations specified with -isystem for some unknown reason. In turn -+ dnl this causes clang to use the system's openssl, which conflicts with -+ dnl curl-impersonate's boringssl headers. -+ dnl To prevent that, disable curl's automatic conversion of -I flags to -+ dnl -isystem. - AC_MSG_RESULT([no]) -- fi -+ ;; -+ *) -+ if test "$compiler_id" = "GNU_C" || -+ test "$compiler_id" = "CLANG"; then -+ AC_MSG_RESULT([yes]) -+ tmp_has_include="no" -+ tmp_chg_FLAGS="$CFLAGS" -+ for word1 in $tmp_chg_FLAGS; do -+ case "$word1" in -+ -I*) -+ tmp_has_include="yes" -+ ;; -+ esac -+ done -+ if test "$tmp_has_include" = "yes"; then -+ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` -+ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` -+ CFLAGS="$tmp_chg_FLAGS" -+ squeeze CFLAGS -+ fi -+ tmp_has_include="no" -+ tmp_chg_FLAGS="$CPPFLAGS" -+ for word1 in $tmp_chg_FLAGS; do -+ case "$word1" in -+ -I*) -+ tmp_has_include="yes" -+ ;; -+ esac -+ done -+ if test "$tmp_has_include" = "yes"; then -+ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/^-I/ -isystem /g'` -+ tmp_chg_FLAGS=`echo "$tmp_chg_FLAGS" | "$SED" 's/ -I/ -isystem /g'` -+ CPPFLAGS="$tmp_chg_FLAGS" -+ squeeze CPPFLAGS -+ fi -+ else -+ AC_MSG_RESULT([no]) -+ fi -+ ;; -+ esac - ]) - - -diff --git a/scripts/singleuse.pl b/scripts/singleuse.pl -index 064990226..172bdc2d0 100755 ---- a/scripts/singleuse.pl -+++ b/scripts/singleuse.pl -@@ -56,6 +56,7 @@ my %api = ( - 'curl_easy_escape' => 'API', - 'curl_easy_getinfo' => 'API', - 'curl_easy_init' => 'API', -+ 'curl_easy_impersonate' => 'API', - 'curl_easy_pause' => 'API', - 'curl_easy_perform' => 'API', - 'curl_easy_recv' => 'API', -diff --git a/src/Makefile.am b/src/Makefile.am -index fcc9cfdf9..18766b7dc 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -43,7 +43,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ - -I$(top_srcdir)/lib \ - -I$(top_srcdir)/src - --bin_PROGRAMS = curl -+bin_PROGRAMS = curl-impersonate-chrome - - if BUILD_DOCS - SUBDIRS = ../docs -@@ -57,9 +57,9 @@ AM_CPPFLAGS += -DBUILDING_CURL - include Makefile.inc - - # CURL_FILES comes from Makefile.inc --curl_SOURCES = $(CURL_FILES) -+curl_impersonate_chrome_SOURCES = $(CURL_FILES) - if HAVE_WINDRES --curl_SOURCES += $(CURL_RCFILES) -+curl_impersonate_chrome_SOURCES += $(CURL_RCFILES) - $(CURL_RCFILES): tool_version.h - endif - -@@ -72,9 +72,9 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ - LIBS = $(BLANK_AT_MAKETIME) - - if USE_EXPLICIT_LIB_DEPS --curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ -+curl_impersonate_chrome_LDADD = $(top_builddir)/lib/libcurl-impersonate-chrome.la @LIBCURL_LIBS@ - else --curl_LDADD = $(top_builddir)/lib/libcurl.la @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ -+curl_impersonate_chrome_LDADD = $(top_builddir)/lib/libcurl-impersonate-chrome.la @SSL_LIBS@ @ZLIB_LIBS@ @CURL_NETWORK_AND_TIME_LIBS@ - endif - - # if unit tests are enabled, build a static library to link them with -diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c -index 3259bc7a5..e46fd7539 100644 ---- a/src/tool_cfgable.c -+++ b/src/tool_cfgable.c -@@ -96,6 +96,14 @@ static void free_config_fields(struct OperationConfig *config) - Curl_safefree(config->proto_str); - Curl_safefree(config->proto_redir_str); - -+ // curl-impersonate -+ Curl_safefree(config->ssl_sig_hash_algs); -+ Curl_safefree(config->ssl_cert_compression); -+ Curl_safefree(config->http2_pseudo_headers_order); -+ Curl_safefree(config->http2_settings); -+ Curl_safefree(config->http2_streams); -+ Curl_safefree(config->tls_extension_order); -+ - urlnode = config->url_list; - while(urlnode) { - struct getout *next = urlnode->next; -@@ -176,6 +184,14 @@ static void free_config_fields(struct OperationConfig *config) - Curl_safefree(config->aws_sigv4); - Curl_safefree(config->proto_str); - Curl_safefree(config->proto_redir_str); -+#ifdef USE_ECH -+ Curl_safefree(config->ech); -+ config->ech = NULL; -+ Curl_safefree(config->ech_config); -+ config->ech_config = NULL; -+ Curl_safefree(config->ech_public); -+ config->ech_public = NULL; -+#endif - } - - void config_free(struct OperationConfig *config) -diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h -index dfa74d81f..349a46af6 100644 ---- a/src/tool_cfgable.h -+++ b/src/tool_cfgable.h -@@ -161,8 +161,18 @@ struct OperationConfig { - bool crlf; - char *customrequest; - char *ssl_ec_curves; -+ char *ssl_sig_hash_algs; -+ char *ssl_cert_compression; - char *krblevel; - char *request_target; -+ char *http2_pseudo_headers_order; -+ char *http2_settings; -+ long http2_window_update; -+ long http2_stream_weight; -+ long http2_stream_exclusive; -+ char *http2_streams; -+ bool tls_grease; -+ char *tls_extension_order; - long httpversion; - bool http09_allowed; - bool nobuffer; -@@ -192,6 +202,7 @@ struct OperationConfig { - struct curl_slist *prequote; - long ssl_version; - long ssl_version_max; -+ bool ssl_permute_extensions; - long proxy_ssl_version; - long ip_version; - long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */ -@@ -268,6 +279,8 @@ struct OperationConfig { - bool proxy_ssl_auto_client_cert; /* proxy version of ssl_auto_client_cert */ - char *oauth_bearer; /* OAuth 2.0 bearer token */ - bool noalpn; /* enable/disable TLS ALPN extension */ -+ bool alps; /* enable/disable TLS ALPS extension */ -+ bool noticket; /* enable/disable TLS session ticket */ - char *unix_socket_path; /* path to Unix domain socket */ - bool abstract_unix_socket; /* path to an abstract Unix domain socket */ - bool falsestart; -@@ -298,6 +311,11 @@ struct OperationConfig { - struct State state; /* for create_transfer() */ - bool rm_partial; /* on error, remove partially written output - files */ -+#ifdef USE_ECH -+ char *ech; /* Config set by --ech keywords */ -+ char *ech_config; /* Config set by "--ech esl:" option */ -+ char *ech_public; /* Config set by "--ech pn:" option */ -+#endif - }; - - struct GlobalConfig { -diff --git a/src/tool_getparam.c b/src/tool_getparam.c -index c6a9c9358..2234eb78d 100644 ---- a/src/tool_getparam.c -+++ b/src/tool_getparam.c -@@ -77,6 +77,7 @@ static ParameterError getstr(char **str, const char *val, bool allowblank) - typedef enum { - C_ABSTRACT_UNIX_SOCKET, - C_ALPN, -+ C_ALPS, - C_ALT_SVC, - C_ANYAUTH, - C_APPEND, -@@ -87,6 +88,7 @@ typedef enum { - C_CACERT, - C_CAPATH, - C_CERT, -+ C_CERT_COMPRESSION, - C_CERT_STATUS, - C_CERT_TYPE, - C_CIPHERS, -@@ -123,6 +125,7 @@ typedef enum { - C_DOH_INSECURE, - C_DOH_URL, - C_DUMP_HEADER, -+ C_ECH, - C_EGD_FILE, - C_ENGINE, - C_EPRT, -@@ -166,6 +169,12 @@ typedef enum { - C_HTTP1_1, - C_HTTP2, - C_HTTP2_PRIOR_KNOWLEDGE, -+ C_HTTP2_PSEUDO_HEADERS_ORDER, -+ C_HTTP2_SETTINGS, -+ C_HTTP2_WINDOW_UPDATE, -+ C_HTTP2_STREAM_EXCLUSIVE, -+ C_HTTP2_STREAM_WEIGHT, -+ C_HTTP2_STREAMS, - C_HTTP3, - C_HTTP3_ONLY, - C_IGNORE_CONTENT_LENGTH, -@@ -283,6 +292,7 @@ typedef enum { - C_SESSIONID, - C_SHOW_ERROR, - C_SILENT, -+ C_SIGNATURE_HASHES, - C_SOCKS4, - C_SOCKS4A, - C_SOCKS5, -@@ -312,6 +322,10 @@ typedef enum { - C_TFTP_NO_OPTIONS, - C_TIME_COND, - C_TLS_MAX, -+ C_TLS_SESSION_TICKET, -+ C_TLS_EXTENSION_ORDER, -+ C_TLS_PERMUTE_EXTENSIONS, -+ C_TLS_GREASE, - C_TLS13_CIPHERS, - C_TLSAUTHTYPE, - C_TLSPASSWORD, -@@ -358,6 +372,7 @@ struct LongShort { - static const struct LongShort aliases[]= { - {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET}, - {"alpn", ARG_BOOL, ' ', C_ALPN}, -+ {"alps", ARG_BOOL, ' ', C_ALPS}, // curl-impersonate - {"alt-svc", ARG_STRG, ' ', C_ALT_SVC}, - {"anyauth", ARG_BOOL, ' ', C_ANYAUTH}, - {"append", ARG_BOOL, 'a', C_APPEND}, -@@ -368,6 +383,7 @@ static const struct LongShort aliases[]= { - {"cacert", ARG_FILE, ' ', C_CACERT}, - {"capath", ARG_FILE, ' ', C_CAPATH}, - {"cert", ARG_FILE, 'E', C_CERT}, -+ {"cert-compression", ARG_STRG, ' ', C_CERT_COMPRESSION}, // curl-impersonate - {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS}, - {"cert-type", ARG_STRG, ' ', C_CERT_TYPE}, - {"ciphers", ARG_STRG, ' ', C_CIPHERS}, -@@ -404,6 +420,9 @@ static const struct LongShort aliases[]= { - {"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE}, - {"doh-url" , ARG_STRG, ' ', C_DOH_URL}, - {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER}, -+#ifdef USE_ECH -+ {"ech", ARG_STRG, ' ', C_ECH}, // curl-impersonate -+#endif - {"egd-file", ARG_STRG, ' ', C_EGD_FILE}, - {"engine", ARG_STRG, ' ', C_ENGINE}, - {"eprt", ARG_BOOL, ' ', C_EPRT}, -@@ -447,6 +466,12 @@ static const struct LongShort aliases[]= { - {"http1.1", ARG_NONE, ' ', C_HTTP1_1}, - {"http2", ARG_NONE, ' ', C_HTTP2}, - {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE}, -+ {"http2-pseudo-headers-order", ARG_STRG, ' ', C_HTTP2_PSEUDO_HEADERS_ORDER}, // curl-impersonate -+ {"http2-settings", ARG_STRG, ' ', C_HTTP2_SETTINGS}, // curl-impersonate -+ {"http2-stream-exclusive", ARG_STRG, ' ', C_HTTP2_STREAM_EXCLUSIVE}, // curl-impersonate -+ {"http2-stream-weight", ARG_STRG, ' ', C_HTTP2_STREAM_WEIGHT}, // curl-impersonate -+ {"http2-streams", ARG_STRG, ' ', C_HTTP2_STREAMS}, // curl-impersonate -+ {"http2-window-update", ARG_STRG, ' ', C_HTTP2_WINDOW_UPDATE}, // curl-impersonate - {"http3", ARG_NONE, ' ', C_HTTP3}, - {"http3-only", ARG_NONE, ' ', C_HTTP3_ONLY}, - {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH}, -@@ -563,6 +588,7 @@ static const struct LongShort aliases[]= { - {"service-name", ARG_STRG, ' ', C_SERVICE_NAME}, - {"sessionid", ARG_BOOL, ' ', C_SESSIONID}, - {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR}, -+ {"signature-hashes", ARG_STRG, ' ', C_SIGNATURE_HASHES}, // curl-impersonate - {"silent", ARG_BOOL, 's', C_SILENT}, - {"socks4", ARG_STRG, ' ', C_SOCKS4}, - {"socks4a", ARG_STRG, ' ', C_SOCKS4A}, -@@ -592,7 +618,11 @@ static const struct LongShort aliases[]= { - {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE}, - {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS}, - {"time-cond", ARG_STRG, 'z', C_TIME_COND}, -+ {"tls-extension-order", ARG_STRG, ' ', C_TLS_EXTENSION_ORDER}, // curl-impersonate -+ {"tls-grease", ARG_BOOL, ' ', C_TLS_GREASE}, // curl-impersonate - {"tls-max", ARG_STRG, ' ', C_TLS_MAX}, -+ {"tls-permute-extensions", ARG_BOOL, ' ', C_TLS_PERMUTE_EXTENSIONS}, // curl-impersonate -+ {"tls-session-ticket", ARG_BOOL, ' ', C_TLS_SESSION_TICKET}, // curl-impersonate - {"tls13-ciphers", ARG_STRG, ' ', C_TLS13_CIPHERS}, - {"tlsauthtype", ARG_STRG, ' ', C_TLSAUTHTYPE}, - {"tlspassword", ARG_STRG, ' ', C_TLSPASSWORD}, -@@ -1434,6 +1464,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - case C_ALPN: /* --alpn */ - config->noalpn = (!toggle)?TRUE:FALSE; - break; -+ case C_ALPS: /* --alps curl-impersonate */ -+ config->alps = toggle; -+ break; - case C_LIMIT_RATE: /* --limit-rate */ - err = GetSizeParameter(global, nextarg, "rate", &value); - if(!err) { -@@ -1865,6 +1898,18 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - case C_TLS_MAX: /* --tls-max */ - err = str2tls_max(&config->ssl_version_max, nextarg); - break; -+ case C_TLS_SESSION_TICKET: /* --tls-session-ticket curl-impersonate */ -+ config->noticket = (!toggle)?TRUE:FALSE; -+ break; -+ case C_TLS_PERMUTE_EXTENSIONS: /* --tls-permute-extensions curl-impersonate */ -+ config->ssl_permute_extensions = toggle; -+ break; -+ case C_TLS_EXTENSION_ORDER: /* --tls-extension-order curl-impersonate */ -+ err = getstr(&config->tls_extension_order, nextarg, ALLOW_BLANK); -+ break; -+ case C_TLS_GREASE: /* --tls-grease curl-impersonate */ -+ config->tls_grease = toggle; -+ break; - case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */ - config->suppress_connect_headers = toggle; - break; -@@ -1914,6 +1959,39 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - return PARAM_LIBCURL_DOESNT_SUPPORT; - sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); - break; -+ case C_HTTP2_PSEUDO_HEADERS_ORDER: /* --http2-pseudo-headers-order curl-impersonate */ -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = getstr(&config->http2_pseudo_headers_order, nextarg, ALLOW_BLANK); -+ break; -+ case C_HTTP2_SETTINGS: /* --http2-settings curl-impersonate */ -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = getstr(&config->http2_settings, nextarg, ALLOW_BLANK); -+ break; -+ case C_HTTP2_STREAM_EXCLUSIVE: -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = str2num(&config->http2_stream_exclusive, nextarg); -+ if(config->http2_stream_exclusive < 0) return PARAM_BAD_NUMERIC; -+ break; -+ case C_HTTP2_STREAM_WEIGHT: -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = str2num(&config->http2_stream_weight, nextarg); -+ if(config->http2_stream_weight < 0) return PARAM_BAD_NUMERIC; -+ break; -+ case C_HTTP2_WINDOW_UPDATE: /* --http2-window-update curl-impersonate */ -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = str2num(&config->http2_window_update, nextarg); -+ if(config->http2_window_update < -1) return PARAM_BAD_NUMERIC; -+ break; -+ case C_HTTP2_STREAMS: /* --http2-streams curl-impersonate */ -+ if(!feature_http2) -+ return PARAM_LIBCURL_DOESNT_SUPPORT; -+ err = getstr(&config->http2_streams, nextarg, ALLOW_BLANK); -+ break; - case C_HTTP3: /* --http3: */ - /* Try HTTP/3, allow fallback */ - if(!feature_http3) -@@ -2033,6 +2111,18 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - case C_DUMP_HEADER: /* --dump-header */ - err = getstr(&config->headerfile, nextarg, DENY_BLANK); - break; -+#ifdef USE_ECH -+ case C_ECH: /* --ech curl-impersonate */ -+ if(strlen(nextarg) != 6 || !strncasecompare("GREASE", nextarg, 6)) { -+ warnf(global, "Only GREASE is supported for --ech."); -+ return PARAM_BAD_USE; /* */ -+ } -+ else { -+ /* Simple case: just a string, with a keyword */ -+ getstr(&config->ech, nextarg, ALLOW_BLANK); -+ } -+ break; -+#endif - case C_REFERER: { /* --referer */ - char *ptr = strstr(nextarg, ";auto"); - if(ptr) { -@@ -2051,6 +2141,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - cleanarg(clearthis); - GetFileAndPassword(nextarg, &config->cert, &config->key_passwd); - break; -+ case C_CERT_COMPRESSION: /* --cert-compression curl-impersonate */ -+ err = getstr(&config->ssl_cert_compression, nextarg, ALLOW_BLANK); -+ break; - case C_CACERT: /* --cacert */ - err = getstr(&config->cacert, nextarg, DENY_BLANK); - break; -@@ -2555,6 +2648,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ - case C_SILENT: /* --silent */ - global->silent = toggle; - break; -+ case C_SIGNATURE_HASHES: /* --signature-hashes */ -+ err = getstr(&config->ssl_sig_hash_algs, nextarg, ALLOW_BLANK); -+ break; - case C_SHOW_ERROR: /* --show-error */ - global->showerror = toggle; - break; -diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c -index 5d9364405..f346f8e0c 100644 ---- a/src/tool_listhelp.c -+++ b/src/tool_listhelp.c -@@ -111,6 +111,27 @@ const struct helptxt helptext[] = { - {" --curves ", - "(EC) TLS key exchange algorithms to request", - CURLHELP_TLS}, -+ {" --signature-hashes ", -+ "TLS signature hash algorithm(s) to use", -+ CURLHELP_TLS}, -+ {" --cert-compression ", -+ "TLS cert compressions algorithm(s) to use", -+ CURLHELP_TLS}, -+ {" --no-tls-session-ticket", -+ "Disable the TLS session ticket extension", -+ CURLHELP_TLS}, -+ {" --http2-pseudo-headers-order", -+ "Change the order of the HTTP2 pseudo headers", -+ CURLHELP_HTTP}, -+ {" --http2-settings", -+ "Change the order and values of the HTTP2 settings frame, e.g. 1:65536;2:0;4:6291456;6:262144", -+ CURLHELP_HTTP}, -+ {" --http2-window-update", -+ "Change the initial value for window update", -+ CURLHELP_HTTP}, -+ {" --tls-permute-extensions", -+ "Enable BoringSSL TLS extensions permutations on client hello", -+ CURLHELP_TLS}, - {"-d, --data ", - "HTTP POST data", - CURLHELP_IMPORTANT | CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD}, -@@ -168,6 +189,11 @@ const struct helptxt helptext[] = { - {"-D, --dump-header ", - "Write the received headers to ", - CURLHELP_HTTP | CURLHELP_FTP}, -+#ifdef USE_ECH -+ {" --ech ", -+ "Encrypted Client Hello controls", -+ CURLHELP_TLS}, -+#endif - {" --egd-file ", - "EGD socket path for random data", - CURLHELP_TLS}, -@@ -396,6 +422,9 @@ const struct helptxt helptext[] = { - {" --no-alpn", - "Disable the ALPN TLS extension", - CURLHELP_TLS | CURLHELP_HTTP}, -+ {" --alps", -+ "Enable the ALPS TLS extension", -+ CURLHELP_TLS | CURLHELP_HTTP}, - {"-N, --no-buffer", - "Disable buffering of the output stream", - CURLHELP_CURL}, -diff --git a/src/tool_operate.c b/src/tool_operate.c -index 7e2c1eefe..8f96c7b08 100644 ---- a/src/tool_operate.c -+++ b/src/tool_operate.c -@@ -1510,6 +1510,36 @@ static CURLcode single_transfer(struct GlobalConfig *global, - return result; - } - -+ if(config->http2_pseudo_headers_order) -+ my_setopt_str(curl, -+ CURLOPT_HTTP2_PSEUDO_HEADERS_ORDER, -+ config->http2_pseudo_headers_order); -+ -+ if(config->http2_settings) -+ my_setopt_str(curl, -+ CURLOPT_HTTP2_SETTINGS, -+ config->http2_settings); -+ -+ if(config->http2_window_update) -+ my_setopt(curl, -+ CURLOPT_HTTP2_WINDOW_UPDATE, -+ config->http2_window_update); -+ -+ if(config->http2_stream_exclusive) -+ my_setopt(curl, -+ CURLOPT_STREAM_EXCLUSIVE, -+ config->http2_stream_exclusive); -+ -+ if(config->http2_stream_weight) -+ my_setopt(curl, -+ CURLOPT_STREAM_WEIGHT, -+ config->http2_stream_weight); -+ -+ if(config->http2_streams) -+ my_setopt_str(curl, -+ CURLOPT_HTTP2_STREAMS, -+ config->http2_streams); -+ - } /* (proto_http) */ - - if(proto_ftp) -@@ -1598,6 +1628,14 @@ static CURLcode single_transfer(struct GlobalConfig *global, - if(config->ssl_ec_curves) - my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves); - -+ if(config->ssl_sig_hash_algs) -+ my_setopt_str(curl, CURLOPT_SSL_SIG_HASH_ALGS, -+ config->ssl_sig_hash_algs); -+ -+ if(config->ssl_cert_compression) -+ my_setopt_str(curl, CURLOPT_SSL_CERT_COMPRESSION, -+ config->ssl_cert_compression); -+ - if(config->writeout) - my_setopt_str(curl, CURLOPT_CERTINFO, 1L); - -@@ -1930,6 +1968,19 @@ static CURLcode single_transfer(struct GlobalConfig *global, - my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS, - config->proxy_cipher13_list); - -+ /* curl-impersonate */ -+ if(config->ssl_permute_extensions) -+ my_setopt(curl, CURLOPT_SSL_PERMUTE_EXTENSIONS, 1L); -+ -+ /* curl-impersonate */ -+ if (config->tls_grease) -+ my_setopt(curl, CURLOPT_TLS_GREASE, 1L); -+ -+ /* curl-impersonate */ -+ if(config->tls_extension_order) -+ // printf("setting is %s\n", config->tls_extension_order); -+ my_setopt_str(curl, CURLOPT_TLS_EXTENSION_ORDER, config->tls_extension_order); -+ - /* new in libcurl 7.9.2: */ - if(config->disable_epsv) - /* disable it */ -@@ -2139,6 +2190,18 @@ static CURLcode single_transfer(struct GlobalConfig *global, - my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); - } - -+ if(config->alps) { -+ my_setopt(curl, CURLOPT_SSL_ENABLE_ALPS, 1L); -+ } -+ -+ if (config->noticket) { -+ my_setopt(curl, CURLOPT_SSL_ENABLE_TICKET, 0L); -+ } -+ -+ // curl-impersonate: always enable thess two for browsers -+ my_setopt(curl, CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, 1L); -+ my_setopt(curl, CURLOPT_TLS_STATUS_REQUEST, 1L); -+ - /* new in 7.40.0, abstract support added in 7.53.0 */ - if(config->unix_socket_path) { - if(config->abstract_unix_socket) { -@@ -2187,6 +2250,16 @@ static CURLcode single_transfer(struct GlobalConfig *global, - if(config->hsts) - my_setopt_str(curl, CURLOPT_HSTS, config->hsts); - -+#ifdef USE_ECH -+ /* only if enabled in configure */ -+ if(config->ech) /* only if set (optional) */ -+ my_setopt_str(curl, CURLOPT_ECH, config->ech); -+ if(config->ech_public) /* only if set (optional) */ -+ my_setopt_str(curl, CURLOPT_ECH, config->ech_public); -+ if(config->ech_config) /* only if set (optional) */ -+ my_setopt_str(curl, CURLOPT_ECH, config->ech_config); -+#endif -+ - /* initialize retry vars for loop below */ - per->retry_sleep_default = (config->retry_delay) ? - config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ -diff --git a/src/tool_setopt.c b/src/tool_setopt.c -index 656adbda8..d149ae238 100644 ---- a/src/tool_setopt.c -+++ b/src/tool_setopt.c -@@ -163,6 +163,10 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = { - NV1(CURLOPT_SSL_VERIFYHOST, 1), - NV1(CURLOPT_SSL_ENABLE_NPN, 1), - NV1(CURLOPT_SSL_ENABLE_ALPN, 1), -+ NV1(CURLOPT_SSL_ENABLE_TICKET, 1), -+ NV1(CURLOPT_SSL_PERMUTE_EXTENSIONS, 1), -+ NV1(CURLOPT_TLS_SIGNED_CERT_TIMESTAMPS, 1), -+ NV1(CURLOPT_TLS_STATUS_REQUEST, 1), - NV1(CURLOPT_TCP_NODELAY, 1), - NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1), - NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1), -diff --git a/tests/.gitignore b/tests/.gitignore -index f08407f52..42b5430ca 100644 ---- a/tests/.gitignore -+++ b/tests/.gitignore -@@ -27,3 +27,5 @@ testcurl.pdf - *.port - config - second-hsts.txt -+runtests.1 -+testcurl.1 -diff --git a/tests/CI.md b/tests/CI.md -index 0d3d1108e..16aba0830 100644 ---- a/tests/CI.md -+++ b/tests/CI.md -@@ -6,8 +6,8 @@ SPDX-License-Identifier: curl - - # Continuous Integration for curl - --Curl runs in many different environments, so every change is run against a large --number of test suites. -+Curl runs in many different environments, so every change is run against a -+large number of test suites. - - Every pull request is verified for each of the following: - -@@ -22,10 +22,10 @@ Every pull request is verified for each of the following: - - ... code coverage does not shrink drastically - - ... different TLS backends still compile and pass tests - --If the pull-request fails one of these tests, it will show up as a red X and --you are expected to fix the problem. If you do not understand when the issue is --or have other problems to fix the complaint, just ask and other project --members will likely be able to help out. -+If the pull-request fails one of these tests, it shows up as a red X and you -+are expected to fix the problem. If you do not understand when the issue is or -+have other problems to fix the complaint, just ask and other project members -+can likely help out. - - Consider the following table while looking at pull request failures: - -@@ -58,7 +58,7 @@ are configured: - - GitHub Actions runs the following tests: - --- Mac OS tests with a variety of different compilation options -+- macOS tests with a variety of different compilation options - - Fuzz tests ([see the curl-fuzzer repo for more - info](https://github.com/curl/curl-fuzzer)). - - Curl compiled using the Rust TLS backend with Hyper -@@ -68,16 +68,7 @@ These are each configured in different files in `.github/workflows`. - - ### Azure - --The following tests are run in Microsoft Azure CI environment: -- --- Ubuntu tests with a variety of different compilation options. --- Windows tests with a variety of different compilation options. -- --These are all configured in `.azure-pipelines.yml`. -- --As of November 2021 `@bagder` and `@mback2k` are the only people with --administrator access to the Azure CI environment. Additional admins/group --members can be added on request. -+Not used anymore. - - ### AppVeyor - -@@ -107,11 +98,4 @@ admins/group members can be added on request. - - ### Cirrus CI - --Cirrus CI runs a basic test suite on FreeBSD and Windows. This is configured in --`.cirrus.yml`. -- --You can [view the full list of CI jobs on Cirrus CI's --website](https://cirrus-ci.com/github/curl/curl). -- --`@bagder` has access to edit the "Project Settings" on that page. Additional --admins/group members can be added on request. -+Not used anymore. -diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt -index 82c651167..165b49dfe 100644 ---- a/tests/CMakeLists.txt -+++ b/tests/CMakeLists.txt -@@ -21,35 +21,92 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --set(CMAKE_UNITY_BUILD OFF) -+option(CURL_TEST_BUNDLES "Bundle libtest and unittest tests into single binaries" OFF) -+ -+find_program(TEST_NGHTTPX "nghttpx") -+if(NOT TEST_NGHTTPX) -+ set(TEST_NGHTTPX "nghttpx") -+endif() -+mark_as_advanced(TEST_NGHTTPX) -+# Consumed variables: TEST_NGHTTPX -+configure_file("config.in" "${CMAKE_CURRENT_BINARY_DIR}/config" @ONLY) - - add_custom_target(testdeps) --add_subdirectory(data) --add_subdirectory(libtest) -+add_subdirectory(http) -+add_subdirectory(http/clients) - add_subdirectory(server) -+add_subdirectory(libtest) - add_subdirectory(unit) -+add_subdirectory(certs EXCLUDE_FROM_ALL) - --function(add_runtests targetname test_flags) -+function(add_runtests _targetname _test_flags) -+ if(CURL_TEST_BUNDLES) -+ set(_test_flags "${_test_flags} -bundle") -+ endif() -+ # Skip walking through dependent targets before running tests in CI. -+ # This avoids: GNU Make doing a slow re-evaluation of all targets and -+ # skipping them, MSBuild doing a re-evaluation, and actually rebuilding them. -+ unset(_depends) -+ if(NOT _targetname STREQUAL "test-ci") -+ set(_depends "testdeps") -+ endif() - # Use a special '$TFLAGS' placeholder as last argument which will be - # replaced by the contents of the environment variable in runtests.pl. - # This is a workaround for CMake's limitation where commands executed by - # 'make' or 'ninja' cannot portably reference environment variables. -- string(REPLACE " " ";" test_flags_list "${test_flags}") -- add_custom_target(${targetname} -+ string(REPLACE " " ";" _test_flags_list "${_test_flags}") -+ add_custom_target(${_targetname} - COMMAND - "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runtests.pl" -- ${test_flags_list} -+ ${_test_flags_list} - "\$TFLAGS" -- DEPENDS testdeps -+ DEPENDS "${_depends}" - VERBATIM USES_TERMINAL - ) - endfunction() - -+function(add_pytest _targetname _test_flags) -+ unset(_depends) -+ if(NOT _targetname STREQUAL "pytest-ci") -+ set(_depends "test-http-clients") -+ endif() -+ string(REPLACE " " ";" _test_flags_list "${_test_flags}") -+ add_custom_target(${_targetname} -+ COMMAND pytest ${_test_flags_list} "${CMAKE_CURRENT_SOURCE_DIR}/http" -+ DEPENDS "${_depends}" -+ VERBATIM USES_TERMINAL -+ ) -+endfunction() -+ -+# Create configurehelp.pm, used by tests needing to run the C preprocessor. -+if(MSVC OR CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") -+ set(CURL_CPP "\"${CMAKE_C_COMPILER}\" -E") -+ if(APPLE AND CMAKE_OSX_SYSROOT) -+ set(CURL_CPP "${CURL_CPP} -isysroot ${CMAKE_OSX_SYSROOT}") -+ endif() -+ # Add header directories, like autotools builds do. -+ get_property(_include_dirs TARGET ${LIB_SELECTED} PROPERTY INCLUDE_DIRECTORIES) -+ foreach(_include_dir IN LISTS _include_dirs) -+ set(CURL_CPP "${CURL_CPP} -I${_include_dir}") -+ endforeach() -+else() -+ set(CURL_CPP "cpp") -+endif() -+# Generate version script for the linker, for versioned symbols. -+# Consumed variable: -+# CURL_CPP -+configure_file( -+ "${CMAKE_CURRENT_SOURCE_DIR}/configurehelp.pm.in" -+ "${CMAKE_CURRENT_BINARY_DIR}/configurehelp.pm" @ONLY) -+ - add_runtests(test-quiet "-a -s") - add_runtests(test-am "-a -am") - add_runtests(test-full "-a -p -r") --# ~flaky means that it'll ignore results of tests using the flaky keyword -+# ~flaky means that it ignores results of tests using the flaky keyword - add_runtests(test-nonflaky "-a -p ~flaky ~timing-dependent") --add_runtests(test-ci "-a -p ~flaky ~timing-dependent -r -rm") --add_runtests(test-torture "-a -t") -+add_runtests(test-ci "-a -p ~flaky ~timing-dependent -r -rm -j20") -+add_runtests(test-torture "-a -t -j20") - add_runtests(test-event "-a -e") -+ -+add_pytest(curl-pytest "") -+add_pytest(curl-pytest-ci "-v") -diff --git a/tests/FILEFORMAT.md b/tests/FILEFORMAT.md -index b594fc113..aa80b8168 100644 ---- a/tests/FILEFORMAT.md -+++ b/tests/FILEFORMAT.md -@@ -23,9 +23,9 @@ with a `testcase` tag, which encompasses the remainder of the file. - # Preprocessing - - When a test is to be executed, the source file is first preprocessed and --variables are substituted by their respective contents and the output --version of the test file is stored as `%LOGDIR/testNUM`. That version is what --will be read and used by the test servers. -+variables are substituted by their respective contents and the output version -+of the test file is stored as `%LOGDIR/testNUM`. That version is what is read -+and used by the test servers. - - ## Base64 Encoding - -@@ -80,7 +80,7 @@ This instruction allows a test case to include another file. It is helpful to - remember that the ordinary variables are expanded before the include happens - so `%LOGDIR` and the others can be used in the include line. - --The file name cannot contain `%` as that letter is used to end the name for -+The filename cannot contain `%` as that letter is used to end the name for - the include instruction: - - %include filename% -@@ -89,7 +89,7 @@ the include instruction: - - Lines in the test file can be made to appear conditionally on a specific - feature (see the "features" section below) being set or not set. If the --specific feature is present, the following lines will be output, otherwise it -+specific feature is present, the following lines are output, otherwise it - outputs nothing, until a following else or `endif` clause. Like this: - - %if brotli -@@ -116,44 +116,44 @@ Nested conditions are supported. - - # Variables - --When the test is preprocessed, a range of "variables" in the test file will be -+When the test is preprocessed, a range of "variables" in the test file is - replaced by their content at that time. - - Available substitute variables include: - --- `%CLIENT6IP` - IPv6 address of the client running curl -+- `%CLIENT6IP` - IPv6 address of the client running curl (including brackets) -+- `%CLIENT6IP-NB` - IPv6 address of the client running curl (no brackets) - - `%CLIENTIP` - IPv4 address of the client running curl - - `%CURL` - Path to the curl executable -+- `%DATE` - current YYYY-MM-DD date -+- `%DEV_NULL` - Null device (e.g. /dev/null) - - `%FILE_PWD` - Current directory, on Windows prefixed with a slash - - `%FTP6PORT` - IPv6 port number of the FTP server - - `%FTPPORT` - Port number of the FTP server - - `%FTPSPORT` - Port number of the FTPS server - - `%FTPTIME2` - Timeout in seconds that should be just sufficient to receive a - response from the test FTP server --- `%FTPTIME3` - Even longer than `%FTPTIME2` - - `%GOPHER6PORT` - IPv6 port number of the Gopher server - - `%GOPHERPORT` - Port number of the Gopher server - - `%GOPHERSPORT` - Port number of the Gophers server - - `%HOST6IP` - IPv6 address of the host running this test - - `%HOSTIP` - IPv4 address of the host running this test -+- `%HTTP2PORT` - Port number of the HTTP/2 server - - `%HTTP6PORT` - IPv6 port number of the HTTP server - - `%HTTPPORT` - Port number of the HTTP server --- `%HTTP2PORT` - Port number of the HTTP/2 server - - `%HTTPSPORT` - Port number of the HTTPS server - - `%HTTPSPROXYPORT` - Port number of the HTTPS-proxy - - `%HTTPTLS6PORT` - IPv6 port number of the HTTP TLS server - - `%HTTPTLSPORT` - Port number of the HTTP TLS server - - `%HTTPUNIXPATH` - Path to the Unix socket of the HTTP server --- `%SOCKSUNIXPATH` - Path to the Unix socket of the SOCKS server - - `%IMAP6PORT` - IPv6 port number of the IMAP server - - `%IMAPPORT` - Port number of the IMAP server - - `%LOGDIR` - Log directory relative to %PWD - - `%MQTTPORT` - Port number of the MQTT server --- `%TELNETPORT` - Port number of the telnet server - - `%NOLISTENPORT` - Port number where no service is listening - - `%POP36PORT` - IPv6 port number of the POP3 server - - `%POP3PORT` - Port number of the POP3 server --- `%POSIX_PWD` - Current directory somewhat mingw friendly -+- `%POSIX_PWD` - Current directory somewhat MinGW friendly - - `%PROXYPORT` - Port number of the HTTP proxy - - `%PWD` - Current directory - - `%RTSP6PORT` - IPv6 port number of the RTSP server -@@ -163,15 +163,18 @@ Available substitute variables include: - - `%SMTP6PORT` - IPv6 port number of the SMTP server - - `%SMTPPORT` - Port number of the SMTP server - - `%SOCKSPORT` - Port number of the SOCKS4/5 server -+- `%SOCKSUNIXPATH` - Path to the Unix socket of the SOCKS server - - `%SRCDIR` - Full path to the source dir -+- `%SSH_PWD` - Current directory friendly for the SSH server - - `%SSHPORT` - Port number of the SCP/SFTP server - - `%SSHSRVMD5` - MD5 of SSH server's public key - - `%SSHSRVSHA256` - SHA256 of SSH server's public key --- `%SSH_PWD` - Current directory friendly for the SSH server -+- `%TELNETPORT` - Port number of the telnet server - - `%TESTNUMBER` - Number of the test case - - `%TFTP6PORT` - IPv6 port number of the TFTP server - - `%TFTPPORT` - Port number of the TFTP server - - `%USER` - Login ID of the user running the test -+- `%VERNUM` - the version number of the tested curl (without -DEV) - - `%VERSION` - the full version number of the tested curl - - # `` -@@ -191,13 +194,13 @@ requests curl sends - been run ended up correct - - Each main section has a number of available subsections that can be specified, --that will be checked/used if specified. -+that are checked/used if specified. - - ## `` - - ### `` - A newline-separated list of keywords describing what this test case uses and --tests. Try to use already used keywords. These keywords will be used for -+tests. Try to use already used keywords. These keywords are used for - statistical/informational purposes and for choosing or skipping classes of - tests. Keywords must begin with an alphabetic character, `-`, `[` or `{` and - may actually consist of multiple words separated by spaces which are treated -@@ -227,24 +230,24 @@ arrived safely. Set `nocheck="yes"` to prevent the test script from verifying - the arrival of this data. - - If the data contains `swsclose` anywhere within the start and end tag, and --this is an HTTP test, then the connection will be closed by the server after --this response is sent. If not, the connection will be kept persistent. -+this is an HTTP test, then the connection is closed by the server after this -+response is sent. If not, the connection is kept persistent. - - If the data contains `swsbounce` anywhere within the start and end tag, the --HTTP server will detect if this is a second request using the same test and --part number and will then increase the part number with one. This is useful --for auth tests and similar. -+HTTP server detects if this is a second request using the same test and part -+number and then increases the part number with one. This is useful for auth -+tests and similar. - --`sendzero=yes` means that the (FTP) server will "send" the data even if the --size is zero bytes. Used to verify curl's behavior on zero bytes transfers. -+`sendzero=yes` means that the (FTP) server "sends" the data even if the size -+is zero bytes. Used to verify curl's behavior on zero bytes transfers. - - `base64=yes` means that the data provided in the test-file is a chunk of data - encoded with base64. It is the only way a test case can contain binary --data. (This attribute can in fact be used on any section, but it doesn't make -+data. (This attribute can in fact be used on any section, but it does not make - much sense for other sections than "data"). - --`hex=yes` means that the data is a sequence of hex pairs. It will get decoded --and used as "raw" data. -+`hex=yes` means that the data is a sequence of hex pairs. It gets decoded and -+used as "raw" data. - - `nonewline=yes` means that the last byte (the trailing newline character) - should be cut off from the data before sending or comparing it. -@@ -253,10 +256,10 @@ should be cut off from the data before sending or comparing it. - the source file. Note that this makes runtests.pl parse and "guess" what is a - header and what is not in order to apply the CRLF line endings appropriately. - --For FTP file listings, the `` section will be used *only* if you make --sure that there has been a CWD done first to a directory named `test-[NUM]` --where `NUM` is the test case number. Otherwise the ftp server can't know from --which test file to load the list content. -+For FTP file listings, the `` section is be used *only* if you make sure -+that there has been a CWD done first to a directory named `test-[NUM]` where -+`NUM` is the test case number. Otherwise the ftp server cannot know from which -+test file to load the list content. - - ### `` - -@@ -287,8 +290,8 @@ Address type and address details as logged by the SOCKS proxy. - - ### `` - if the data is sent but this is what should be checked afterwards. If --`nonewline=yes` is set, runtests will cut off the trailing newline from the --data before comparing with the one actually received by the client. -+`nonewline=yes` is set, runtests cuts off the trailing newline from the data -+before comparing with the one actually received by the client. - - Use the `mode="text"` attribute if the output is in text mode on platforms - that have a text/binary difference. -@@ -298,11 +301,11 @@ The contents of numbered `datacheck` sections are appended to the non-numbered - one. - - ### `` --number to return on a ftp SIZE command (set to -1 to make this command fail) -+number to return on an ftp SIZE command (set to -1 to make this command fail) - - ### `` - what to send back if the client sends a (FTP) `MDTM` command, set to -1 to --have it return that the file doesn't exist -+have it return that the file does not exist - - ### `` - special purpose server-command to control its behavior *after* the -@@ -314,15 +317,15 @@ For HTTP/HTTPS, these are supported: - ### `` - Special-commands for the server. - --The first line of this file will always be set to `Testnum [number]` by the --test script, to allow servers to read that to know what test the client is --about to issue. -+The first line of this file is always set to `Testnum [number]` by the test -+script, to allow servers to read that to know what test the client is about to -+issue. - - #### For FTP/SMTP/POP/IMAP - - - `REPLY [command] [return value] [response string]` - Changes how the server - responds to the [command]. [response string] is evaluated as a perl string, -- so it can contain embedded \r\n, for example. There's a special [command] -+ so it can contain embedded \r\n, for example. There is a special [command] - named "welcome" (without quotes) which is the string sent immediately on - connect as a welcome. - - `REPLYLF` (like above but sends the response terminated with LF-only and not -@@ -333,11 +336,13 @@ about to issue. - time - - `RETRWEIRDO` - Enable the "weirdo" RETR case when multiple response lines - appear at once when a file is transferred --- `RETRNOSIZE` - Make sure the RETR response doesn't contain the size of the -+- `RETRNOSIZE` - Make sure the RETR response does not contain the size of the - file - - `RETRSIZE [size]` - Force RETR response to contain the specified size --- `NOSAVE` - Don't actually save what is received -+- `NOSAVE` - Do not actually save what is received - - `SLOWDOWN` - Send FTP responses with 0.01 sec delay between each byte -+- `SLOWDOWNDATA` - Send FTP responses with 0.01 sec delay between each data -+ byte - - `PASVBADIP` - makes PASV send back an illegal IP in its 227 response - - `CAPA [capabilities]` - Enables support for and specifies a list of space - separated capabilities to return to the client for the IMAP `CAPABILITY`, -@@ -349,7 +354,7 @@ about to issue. - #### For HTTP/HTTPS - - - `auth_required` if this is set and a POST/PUT is made without auth, the -- server will NOT wait for the full request body to get sent -+ server does NOT wait for the full request body to get sent - - `delay: [msecs]` - delay this amount after connection - - `idle` - do nothing after receiving the request, just "sit idle" - - `stream` - continuously send data to the client, never-ending -@@ -358,12 +363,12 @@ about to issue. - a PUT or POST request - - `rtp: part [num] channel [num] size [num]` - stream a fake RTP packet for - the given part on a chosen channel with the given payload size --- `connection-monitor` - When used, this will log `[DISCONNECT]` to the -+- `connection-monitor` - When used, this logs `[DISCONNECT]` to the - `server.input` log when the connection is disconnected. --- `upgrade` - when an HTTP upgrade header is found, the server will upgrade to -+- `upgrade` - when an HTTP upgrade header is found, the server upgrades to - http2 - - `swsclose` - instruct server to close connection after response --- `no-expect` - don't read the request body if Expect: is present -+- `no-expect` - do not read the request body if Expect: is present - - #### For TFTP - `writedelay: [secs]` delay this amount between reply packets (each packet -@@ -409,28 +414,28 @@ What server(s) this test case requires/uses. Available servers: - - Give only one per line. This subsection is mandatory (use `none` if no servers - are required). Servers that require a special server certificate can have the --PEM certificate file name (found in the `certs` directory) appended to the -+PEM certificate filename (found in the `certs` directory) appended to the - server name separated by a space. - - ### `` - A list of features that MUST be present in the client/library for this test to --be able to run. If a required feature is not present then the test will be --SKIPPED. -+be able to run. If a required feature is not present then the test is SKIPPED. - - Alternatively a feature can be prefixed with an exclamation mark to indicate a --feature is NOT required. If the feature is present then the test will be --SKIPPED. -+feature is NOT required. If the feature is present then the test is SKIPPED. - - Features testable here are: - - - `alt-svc` -+- `AppleIDN` - - `bearssl` - - `brotli` - - `c-ares` - - `CharConv` -+- `codeset-utf8`. If the running codeset is UTF-8 capable. - - `cookies` - - `crypto` --- `debug` -+- `Debug` - - `DoH` - - `getrlimit` - - `GnuTLS` -@@ -441,18 +446,19 @@ Features testable here are: - - `HTTP-auth` - - `http/2` - - `http/3` --- `https-proxy` -+- `HTTPS-proxy` - - `hyper` --- `idn` --- `ipv6` -+- `IDN` -+- `IPv6` - - `Kerberos` --- `large_file` --- `large-time` (time_t is larger than 32 bit) -+- `Largefile` -+- `large-time` (time_t is larger than 32-bit) - - `ld_preload` - - `libssh2` - - `libssh` - - `oldlibssh` (versions before 0.9.4) - - `libz` -+- `local-http`. The HTTP server runs on 127.0.0.1 - - `manual` - - `mbedtls` - - `Mime` -@@ -481,10 +487,11 @@ Features testable here are: - - `threadsafe` - - `Unicode` - - `unittest` --- `unix-sockets` -+- `UnixSockets` - - `verbose-strings` - - `wakeup` - - `win32` -+- `WinIDN` - - `wolfssh` - - `wolfssl` - - `xattr` -@@ -503,13 +510,8 @@ restart servers. - ### `` - A command line that if set gets run by the test script before the test. If an - output is displayed by the command or if the return code is non-zero, the test --will be skipped and the (single-line) output will be displayed as reason for --not running the test. -- --### `` --A command line that if set gets run by the test script after the test. If --the command exists with a non-zero status code, the test will be considered --to have failed. -+is skipped and the (single-line) output is displayed as reason for not running -+the test. - - ### `` - Name of tool to invoke instead of "curl". This tool must be built and exist -@@ -531,26 +533,26 @@ command has been run. - If the variable name has no assignment, no `=`, then that variable is just - deleted. - --### `` -+### `` - Command line to run. - - Note that the URL that gets passed to the server actually controls what data - that is returned. The last slash in the URL must be followed by a number. That --number (N) will be used by the test-server to load test case N and return the --data that is defined within the `` section. -+number (N) is used by the test-server to load test case N and return the data -+that is defined within the `` section. - --If there's no test number found above, the HTTP test server will use the --number following the last dot in the given hostname (made so that a CONNECT --can still pass on test number) so that "foo.bar.123" gets treated as test case -+If there is no test number found above, the HTTP test server uses the number -+following the last dot in the given hostname (made so that a CONNECT can still -+pass on test number) so that "foo.bar.123" gets treated as test case - 123. Alternatively, if an IPv6 address is provided to CONNECT, the last --hexadecimal group in the address will be used as the test number! For example --the address "[1234::ff]" would be treated as test case 255. -+hexadecimal group in the address is used as the test number. For example the -+address "[1234::ff]" would be treated as test case 255. - - Set `type="perl"` to write the test case as a perl script. It implies that --there's no memory debugging and valgrind gets shut off for this test. -+there is no memory debugging and valgrind gets shut off for this test. - - Set `type="shell"` to write the test case as a shell script. It implies that --there's no memory debugging and valgrind gets shut off for this test. -+there is no memory debugging and valgrind gets shut off for this test. - - Set `option="no-output"` to prevent the test script to slap on the `--output` - argument that directs the output to a file. The `--output` is also not added -@@ -562,6 +564,9 @@ otherwise written to verify stdout. - Set `option="no-include"` to prevent the test script to slap on the - `--include` argument. - -+Set `option="no-q"` avoid using `-q` as the first argument in the curl command -+line. -+ - Set `option="binary-trace"` to use `--trace` instead of `--trace-ascii` for - tracing. Suitable for binary-oriented protocols such as MQTT. - -@@ -583,13 +588,22 @@ needed. - This creates the named file with this content before the test case is run, - which is useful if the test case needs a file to act on. - --If `nonewline="yes"` is used, the created file will have the final newline --stripped off. -+If `nonewline="yes"` is used, the created file gets the final newline stripped -+off. -+ -+### `` -+1 to 4 can be appended to 'file' to create more files. -+ -+### `` -+ -+### `` -+ -+### `` - - ### `` - Pass this given data on stdin to the tool. - --If `nonewline` is set, we will cut off the trailing newline of this given data -+If `nonewline` is set, we cut off the trailing newline of this given data - before comparing with the one actually received by the client - - ## `` -@@ -607,10 +621,18 @@ changing protocol data such as port numbers or user-agent strings. - One perl op per line that operates on the protocol dump. This is pretty - advanced. Example: `s/^EPRT .*/EPRT stripped/`. - -+### `` -+A command line that if set gets run by the test script after the test. If the -+command exists with a non-zero status code, the test is considered failed. -+ -+### `` -+A list of directory entries that are checked for after the test has completed -+and that must not exist. A listed entry existing causes the test to fail. -+ - ### `` - --the protocol dump curl should transmit, if `nonewline` is set, we will cut off --the trailing newline of this given data before comparing with the one actually -+the protocol dump curl should transmit, if `nonewline` is set, we cut off the -+trailing newline of this given data before comparing with the one actually - sent by the client The `` and `` rules are applied before - comparisons are made. - -@@ -620,17 +642,20 @@ test. - ### `` - - The protocol dump curl should transmit to an HTTP proxy (when the http-proxy --server is used), if `nonewline` is set, we will cut off the trailing newline --of this given data before comparing with the one actually sent by the client --The `` and `` rules are applied before comparisons are made. -+server is used), if `nonewline` is set, we cut off the trailing newline of -+this given data before comparing with the one actually sent by the client The -+`` and `` rules are applied before comparisons are made. - --### `` -+### `` - This verifies that this data was passed to stderr. - - Use the mode="text" attribute if the output is in text mode on platforms that - have a text/binary difference. - --If `nonewline` is set, we will cut off the trailing newline of this given data -+`crlf=yes` forces the newlines to become CRLF even if not written so in the -+test. -+ -+If `nonewline` is set, we cut off the trailing newline of this given data - before comparing with the one actually received by the client - - ### `` -@@ -639,7 +664,7 @@ This verifies that this data was passed to stdout. - Use the mode="text" attribute if the output is in text mode on platforms that - have a text/binary difference. - --If `nonewline` is set, we will cut off the trailing newline of this given data -+If `nonewline` is set, we cut off the trailing newline of this given data - before comparing with the one actually received by the client - - `crlf=yes` forces the newlines to become CRLF even if not written so in the -@@ -676,8 +701,14 @@ content - - ### `` - --### `` -+### `` - the contents of the upload data curl should have sent - -+`crlf=yes` forces *upload* newlines to become CRLF even if not written so in -+the source file. -+ -+`nonewline=yes` means that the last byte (the trailing newline character) -+should be cut off from the upload data before comparing it. -+ - ### `` - disable - disables the valgrind log check for this test -diff --git a/tests/Makefile.am b/tests/Makefile.am -index a6d0708f7..56329f4a8 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -22,7 +22,14 @@ - # - ########################################################################### - --MANDISTPAGES = runtests.1.dist testcurl.1.dist -+if BUILD_DOCS -+# if we disable man page building, ignore these -+RUNTESTS_DOCS = runtests.1 -+TESTCURL_DOCS = testcurl.1 -+MANFILES = $(RUNTESTS_DOCS) $(TESTCURL_DOCS) -+endif -+ -+CURLPAGES = runtests.md testcurl.md - - # scripts used in test cases - TESTSCRIPTS = \ -@@ -40,19 +47,55 @@ TESTSCRIPTS = \ - test1275.pl \ - test1276.pl \ - test1477.pl \ -+ test1486.pl \ -+ test1488.pl \ - test1544.pl \ -+ test1707.pl \ - test971.pl - --EXTRA_DIST = appveyor.pm azure.pm CMakeLists.txt devtest.pl \ -- dictserver.py directories.pm FILEFORMAT.md processhelp.pm ftpserver.pl \ -- getpart.pm globalconfig.pm http-server.pl http2-server.pl \ -- http3-server.pl memanalyze.pl negtelnetserver.py pathhelp.pm README.md \ -- rtspserver.pl runner.pm runtests.1 runtests.pl secureserver.pl \ -- serverhelp.pm servers.pm smbserver.py sshhelp.pm sshserver.pl \ -- stunnel.pem testcurl.1 testcurl.pl testutil.pm tftpserver.pl util.py \ -- valgrind.pm valgrind.supp $(TESTSCRIPTS) -- --DISTCLEANFILES = configurehelp.pm -+EXTRA_DIST = \ -+ CMakeLists.txt \ -+ FILEFORMAT.md \ -+ README.md \ -+ appveyor.pm \ -+ azure.pm \ -+ devtest.pl \ -+ dictserver.py \ -+ directories.pm \ -+ ech_combos.py \ -+ ech_tests.sh \ -+ ftpserver.pl \ -+ getpart.pm \ -+ globalconfig.pm \ -+ http-server.pl \ -+ http2-server.pl \ -+ http3-server.pl \ -+ memanalyze.pl \ -+ mk-bundle-hints.sh \ -+ mk-bundle.pl \ -+ negtelnetserver.py \ -+ nghttpx.conf \ -+ pathhelp.pm \ -+ processhelp.pm \ -+ requirements.txt \ -+ rtspserver.pl \ -+ runner.pm \ -+ runtests.pl \ -+ secureserver.pl \ -+ serverhelp.pm \ -+ servers.pm \ -+ smbserver.py \ -+ sshhelp.pm \ -+ sshserver.pl \ -+ stunnel.pem \ -+ testcurl.pl \ -+ testutil.pm \ -+ tftpserver.pl \ -+ util.py \ -+ valgrind.pm \ -+ valgrind.supp \ -+ $(TESTSCRIPTS) \ -+ $(CURLPAGES) - - # we have two variables here to make sure DIST_SUBDIRS won't get 'unit' - # added twice as then targets such as 'distclean' misbehave and try to -@@ -75,14 +118,21 @@ CLEANFILES = .http.pid .https.pid .ftp.pid .ftps.pid $(MANDISTPAGES) - curl: - @cd $(top_builddir) && $(MAKE) - -+TEST_COMMON = -+ - if CROSSCOMPILING - TEST = @echo "NOTICE: we can't run the tests when cross-compiling!" -+PYTEST = $(TEST) - else # if not cross-compiling: --TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -+if USE_TEST_BUNDLES -+TEST_COMMON += -bundle -+endif -+ -+TEST = srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl $(TEST_COMMON) - TEST_Q = -a -s - TEST_AM = -a -am - TEST_F = -a -p -r --TEST_T = -a -t -+TEST_T = -a -t -j20 - TEST_E = -a -e - - # ~ means that it will run all tests matching the keyword, but will -@@ -90,9 +140,18 @@ TEST_E = -a -e - TEST_NF = -a -p ~flaky ~timing-dependent - - # special CI target derived from nonflaky with CI-specific flags --TEST_CI = $(TEST_NF) -rm -+TEST_CI = $(TEST_NF) -r -rm -j20 -+ -+PYTEST = pytest - endif - -+CD2NROFF = $(top_srcdir)/scripts/cd2nroff $< >$@ -+ -+SUFFIXES = .1 .md -+ -+.md.1: -+ $(CD2)$(CD2NROFF) -+ - # make sure that PERL is pointing to an executable - perlcheck: - @if ! test -x "$(PERL)"; then echo "No perl!"; exit 2; fi -@@ -121,13 +180,18 @@ torture-test: perlcheck all - event-test: perlcheck all - $(TEST) $(TEST_E) $(TFLAGS) - -+default-pytest: ci-pytest -+ -+ci-pytest: all -+ srcdir=$(srcdir) $(PYTEST) -v $(srcdir)/http -+ - checksrc: - (cd libtest && $(MAKE) checksrc) - (cd unit && $(MAKE) checksrc) - (cd server && $(MAKE) checksrc) - (cd http && $(MAKE) checksrc) - --if CURLDEBUG --# for debug builds, we scan the sources on all regular make invokes --all-local: checksrc --endif -+all-local: $(MANFILES) -+ -+distclean: -+ rm -f $(MANFILES) -diff --git a/tests/README.md b/tests/README.md -index d758d9763..54fb6b3e9 100644 ---- a/tests/README.md -+++ b/tests/README.md -@@ -29,7 +29,7 @@ SPDX-License-Identifier: curl - When you run tests via make, the flags `-a` and `-s` are passed, meaning - to continue running tests even after one fails, and to emit short output. - -- If you'd like to not use those flags, you can run 'runtests.pl' directly. -+ If you would like to not use those flags, you can run 'runtests.pl' directly. - You must `chdir` into the tests directory, then you can run it like so: - - ./runtests.pl 303 410 -@@ -45,8 +45,8 @@ SPDX-License-Identifier: curl - - ## Requires to run - -- - perl (and a unix-style shell) -- - python (and a unix-style shell, for SMB and TELNET tests) -+ - perl (and a Unix-style shell) -+ - python (and a Unix-style shell, for SMB and TELNET tests) - - python-impacket (for SMB tests) - - diff (when a test fails, a diff is shown) - - stunnel (for HTTPS and FTPS tests) -@@ -54,31 +54,37 @@ SPDX-License-Identifier: curl - - nghttpx (for HTTP/2 and HTTP/3 tests) - - An available `en_US.UTF-8` locale - --### Installation of python-impacket -+### Installation of impacket - -- The Python-based test servers support both recent Python 2 and 3. -- You can figure out your default Python interpreter with python -V -+ The Python-based test servers support Python 3. - - Please install python-impacket in the correct Python environment. - You can use pip or your OS' package manager to install 'impacket'. - -- On Debian/Ubuntu the package names are: -+ On Debian/Ubuntu the package name is 'python3-impacket' - -- - Python 2: 'python-impacket' -- - Python 3: 'python3-impacket' -+ On FreeBSD the package name is 'py311-impacket' - -- On FreeBSD the package names are: -+ On any system where pip is available: 'python3 -m pip install impacket' - -- - Python 2: 'py27-impacket' -- - Python 3: 'py37-impacket' -+ You may also need to manually install the Python package 'six' -+ as that may be a missing requirement for impacket. - -- On any system where pip is available: -+## Event-based - -- - Python 2: 'pip2 install impacket' -- - Python 3: 'pip3 install impacket' -+ If curl is built with `Debug` enabled (see below), then the `runtests.pl` -+ script offers a `-e` option that makes it perform *event-based*. Such tests -+ invokes the curl tool with `--test-event`, a debug-only option made for this -+ purpose. - -- You may also need to manually install the Python package 'six' -- as that may be a missing requirement for impacket on Python 3. -+ Performing event-based means that the curl tool uses the -+ `curl_multi_socket_action()` API call to drive the transfer(s), instead of -+ the otherwise "normal" functions it would use. This allows us to test drive -+ the socket_action API. Transfers done this way should work exactly the same -+ as with the non-event based API. -+ -+ To be able to use `--test-event` together with `--parallel`, curl requires -+ *libuv* to be present and enabled in the build: `configure --enable-libuv` - - ### Port numbers used by test servers - -@@ -125,13 +131,13 @@ SPDX-License-Identifier: curl - - ### Memory test - -- The test script will check that all allocated memory is freed properly IF -- curl has been built with the `CURLDEBUG` define set. The script will -- automatically detect if that is the case, and it will use the -- `memanalyze.pl` script to analyze the memory debugging output. -+ The test script checks that all allocated memory is freed properly IF curl -+ has been built with the `CURLDEBUG` define set. The script automatically -+ detects if that is the case, and it uses the `memanalyze.pl` script to -+ analyze the memory debugging output. - -- Also, if you run tests on a machine where valgrind is found, the script will -- use valgrind to run the test with (unless you use `-n`) to further verify -+ Also, if you run tests on a machine where valgrind is found, the script uses -+ valgrind to run the test with (unless you use `-n`) to further verify - correctness. - - The `runtests.pl` `-t` option enables torture testing mode. It runs each -@@ -167,7 +173,7 @@ SPDX-License-Identifier: curl - - CURL_DEBUG=ssl curl -v https://curl.se - -- will make the `ssl` connection filter log more details. One may do that for -+ makes the `ssl` connection filter log more details. One may do that for - every filter type and also use a combination of names, separated by `,` or - space. - -@@ -205,7 +211,7 @@ SPDX-License-Identifier: curl - - ggcov -r lib src - -- The text mode tool `gcov` may also be used, but it doesn't handle object -+ The text mode tool `gcov` may also be used, but it does not handle object - files in more than one directory correctly. - - ### Remote testing -@@ -222,7 +228,7 @@ SPDX-License-Identifier: curl - up. Subsets of tests can now be selected by passing keywords to the - runtests.pl script via the make `TFLAGS` variable. - -- New tests are added by finding a free number in `tests/data/Makefile.inc`. -+ New tests are added by finding a free number in `tests/data/Makefile.am`. - - ## Write tests - -@@ -256,7 +262,7 @@ SPDX-License-Identifier: curl - - ### unit tests - -- Unit tests are placed in `tests/unit`. There's a tests/unit/README -+ Unit tests are placed in `tests/unit`. There is a tests/unit/README - describing the specific set of checks and macros that may be used when - writing tests that verify behaviors of specific individual functions. - -diff --git a/tests/certs/CMakeLists.txt b/tests/certs/CMakeLists.txt -new file mode 100644 -index 000000000..f9011b13f ---- /dev/null -+++ b/tests/certs/CMakeLists.txt -@@ -0,0 +1,48 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+find_program(SH_EXECUTABLE "sh") -+mark_as_advanced(SH_EXECUTABLE) -+if(SH_EXECUTABLE) -+ # Get 'CERTCONFIGS', 'GENERATEDCERTS', 'SRPFILES' variables -+ transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+ include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+ -+ add_custom_target(clean-certs -+ COMMAND ${CMAKE_COMMAND} -E remove ${GENERATEDCERTS} -+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -+ ) -+ -+ add_custom_target(build-certs -+ DEPENDS ${CERTCONFIGS} ${SRPFILES} -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genroot.sh" EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" Server-localhost EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" Server-localhost.nn EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" Server-localhost0h EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" Server-localhost-firstSAN EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" Server-localhost-lastSAN EdelCurlRoot -+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/scripts/genserv.sh" stunnel EdelCurlRoot -+ COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/stunnel-sv.pem" "${CMAKE_CURRENT_SOURCE_DIR}/../stunnel.pem" -+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -+ ) -+endif() -diff --git a/tests/certs/EdelCurlRoot-ca.prm b/tests/certs/EdelCurlRoot-ca.prm -index c8e248b3e..cf1b30d23 100644 ---- a/tests/certs/EdelCurlRoot-ca.prm -+++ b/tests/certs/EdelCurlRoot-ca.prm -@@ -1,20 +1,9 @@ - extensions = x509v3 --[ req ] --default_bits = 2048 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = Northern Nowhere Trust Anchor -+ - [ x509v3 ] --basicConstraints = critical,CA:true --keyUsage = critical,keyCertSign,cRLSign --subjectKeyIdentifier = hash -+basicConstraints = critical,CA:true -+keyUsage = critical,keyCertSign,cRLSign -+subjectKeyIdentifier = hash - authorityKeyIdentifier = keyid:always - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info -@@ -27,4 +16,18 @@ authorityInfoAccess = @issuer_info - caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - - [ crl_info ] --URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl -\ No newline at end of file -+URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl -+ -+[ req ] -+default_bits = 2048 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only -+ -+[ req_DN ] -+countryName = "Country Name" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = Northern Nowhere Trust Anchor -diff --git a/tests/certs/Makefile.am b/tests/certs/Makefile.am -index e21cdd5c4..a2b45885a 100644 ---- a/tests/certs/Makefile.am -+++ b/tests/certs/Makefile.am -@@ -25,82 +25,9 @@ AUTOMAKE_OPTIONS = foreign - - SUBDIRS = scripts - --CERTCONFIGS = \ -- EdelCurlRoot-ca.prm \ -- EdelCurlRoot-ca.cnf \ -- Server-localhost-sv.prm \ -- Server-localhost.nn-sv.prm \ -- Server-localhost0h-sv.prm \ -- Server-localhost-firstSAN-sv.prm \ -- Server-localhost-lastSAN-sv.prm \ -- stunnel-sv.prm -+include Makefile.inc - --GENERATEDCERTS = \ -- EdelCurlRoot-ca.cacert \ -- EdelCurlRoot-ca.crt \ -- EdelCurlRoot-ca.csr \ -- EdelCurlRoot-ca.der \ -- EdelCurlRoot-ca.key \ -- Server-localhost-sv.crl \ -- Server-localhost-sv.crt \ -- Server-localhost-sv.csr \ -- Server-localhost-sv.der \ -- Server-localhost-sv.dhp \ -- Server-localhost-sv.key \ -- Server-localhost-sv.pem \ -- Server-localhost-sv.pub.der \ -- Server-localhost-sv.pub.pem \ -- Server-localhost.nn-sv.crl \ -- Server-localhost.nn-sv.crt \ -- Server-localhost.nn-sv.csr \ -- Server-localhost.nn-sv.der \ -- Server-localhost.nn-sv.dhp \ -- Server-localhost.nn-sv.key \ -- Server-localhost.nn-sv.pem \ -- Server-localhost.nn-sv.pub.der \ -- Server-localhost.nn-sv.pub.pem \ -- Server-localhost0h-sv.crl \ -- Server-localhost0h-sv.crt \ -- Server-localhost0h-sv.csr \ -- Server-localhost0h-sv.der \ -- Server-localhost0h-sv.dhp \ -- Server-localhost0h-sv.key \ -- Server-localhost0h-sv.pem \ -- Server-localhost0h-sv.pub.der \ -- Server-localhost0h-sv.pub.pem \ -- Server-localhost-firstSAN-sv.crl \ -- Server-localhost-firstSAN-sv.crt \ -- Server-localhost-firstSAN-sv.csr \ -- Server-localhost-firstSAN-sv.der \ -- Server-localhost-firstSAN-sv.dhp \ -- Server-localhost-firstSAN-sv.key \ -- Server-localhost-firstSAN-sv.pem \ -- Server-localhost-firstSAN-sv.pub.der \ -- Server-localhost-firstSAN-sv.pub.pem \ -- Server-localhost-lastSAN-sv.crl \ -- Server-localhost-lastSAN-sv.crt \ -- Server-localhost-lastSAN-sv.csr \ -- Server-localhost-lastSAN-sv.der \ -- Server-localhost-lastSAN-sv.dhp \ -- Server-localhost-lastSAN-sv.key \ -- Server-localhost-lastSAN-sv.pem \ -- Server-localhost-lastSAN-sv.pub.der \ -- Server-localhost-lastSAN-sv.pub.pem \ -- stunnel-sv.crl \ -- stunnel-sv.crt \ -- stunnel-sv.csr \ -- stunnel-sv.der \ -- stunnel-sv.dhp \ -- stunnel-sv.key \ -- stunnel-sv.pem \ -- stunnel-sv.der \ -- stunnel-sv.pub.pem -- --SRPFILES = \ -- srp-verifier-conf \ -- srp-verifier-db -- --EXTRA_DIST = $(CERTCONFIGS) $(GENERATEDCERTS) $(SRPFILES) -+EXTRA_DIST = $(CERTCONFIGS) $(GENERATEDCERTS) $(SRPFILES) CMakeLists.txt - - # Rebuild the certificates - -@@ -110,7 +37,7 @@ clean-certs: - build-certs: $(srcdir)/EdelCurlRoot-ca.cacert $(srcdir)/Server-localhost-sv.pem \ - $(srcdir)/Server-localhost.nn-sv.pem $(srcdir)/Server-localhost0h-sv.pem \ - $(srcdir)/Server-localhost-firstSAN-sv.pem $(srcdir)/Server-localhost-lastSAN-sv.pem \ -- $(srcdir)/stunnel-sv.pem ../stunnel.pem -+ $(srcdir)/stunnel-sv.pem $(srcdir)/../stunnel.pem - - $(srcdir)/EdelCurlRoot-ca.cacert: - cd $(srcdir); scripts/genroot.sh EdelCurlRoot -@@ -133,5 +60,5 @@ $(srcdir)/Server-localhost-lastSAN-sv.pem: $(srcdir)/EdelCurlRoot-ca.cacert - $(srcdir)/stunnel-sv.pem: $(srcdir)/EdelCurlRoot-ca.cacert - cd $(srcdir); scripts/genserv.sh stunnel EdelCurlRoot - --../stunnel.pem: $(srcdir)/stunnel-sv.pem -+ $(srcdir)/../stunnel.pem: $(srcdir)/stunnel-sv.pem - cp $< $@ -diff --git a/tests/certs/Makefile.inc b/tests/certs/Makefile.inc -new file mode 100644 -index 000000000..032baec24 ---- /dev/null -+++ b/tests/certs/Makefile.inc -@@ -0,0 +1,104 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+CERTCONFIGS = \ -+ EdelCurlRoot-ca.prm \ -+ EdelCurlRoot-ca.cnf \ -+ Server-localhost-sv.prm \ -+ Server-localhost.nn-sv.prm \ -+ Server-localhost0h-sv.prm \ -+ Server-localhost-firstSAN-sv.prm \ -+ Server-localhost-lastSAN-sv.prm \ -+ stunnel-sv.prm -+ -+GENERATEDCERTS = \ -+ EdelCurlRoot-ca.cacert \ -+ EdelCurlRoot-ca.crt \ -+ EdelCurlRoot-ca.csr \ -+ EdelCurlRoot-ca.der \ -+ EdelCurlRoot-ca.key \ -+ Server-localhost-sv.crl \ -+ Server-localhost-sv.crt \ -+ Server-localhost-sv.csr \ -+ Server-localhost-sv.der \ -+ Server-localhost-sv.dhp \ -+ Server-localhost-sv.key \ -+ Server-localhost-sv.pem \ -+ Server-localhost-sv.pub.der \ -+ Server-localhost-sv.pub.pem \ -+ Server-localhost-sv.pubkey-pinned \ -+ Server-localhost.nn-sv.crl \ -+ Server-localhost.nn-sv.crt \ -+ Server-localhost.nn-sv.csr \ -+ Server-localhost.nn-sv.der \ -+ Server-localhost.nn-sv.dhp \ -+ Server-localhost.nn-sv.key \ -+ Server-localhost.nn-sv.pem \ -+ Server-localhost.nn-sv.pub.der \ -+ Server-localhost.nn-sv.pub.pem \ -+ Server-localhost.nn-sv.pubkey-pinned \ -+ Server-localhost0h-sv.crl \ -+ Server-localhost0h-sv.crt \ -+ Server-localhost0h-sv.csr \ -+ Server-localhost0h-sv.der \ -+ Server-localhost0h-sv.dhp \ -+ Server-localhost0h-sv.key \ -+ Server-localhost0h-sv.pem \ -+ Server-localhost0h-sv.pub.der \ -+ Server-localhost0h-sv.pub.pem \ -+ Server-localhost0h-sv.pubkey-pinned \ -+ Server-localhost-firstSAN-sv.crl \ -+ Server-localhost-firstSAN-sv.crt \ -+ Server-localhost-firstSAN-sv.csr \ -+ Server-localhost-firstSAN-sv.der \ -+ Server-localhost-firstSAN-sv.dhp \ -+ Server-localhost-firstSAN-sv.key \ -+ Server-localhost-firstSAN-sv.pem \ -+ Server-localhost-firstSAN-sv.pub.der \ -+ Server-localhost-firstSAN-sv.pub.pem \ -+ Server-localhost-firstSAN-sv.pubkey-pinned \ -+ Server-localhost-lastSAN-sv.crl \ -+ Server-localhost-lastSAN-sv.crt \ -+ Server-localhost-lastSAN-sv.csr \ -+ Server-localhost-lastSAN-sv.der \ -+ Server-localhost-lastSAN-sv.dhp \ -+ Server-localhost-lastSAN-sv.key \ -+ Server-localhost-lastSAN-sv.pem \ -+ Server-localhost-lastSAN-sv.pub.der \ -+ Server-localhost-lastSAN-sv.pub.pem \ -+ Server-localhost-lastSAN-sv.pubkey-pinned \ -+ stunnel-sv.crl \ -+ stunnel-sv.crt \ -+ stunnel-sv.csr \ -+ stunnel-sv.der \ -+ stunnel-sv.dhp \ -+ stunnel-sv.key \ -+ stunnel-sv.pem \ -+ stunnel-sv.der \ -+ stunnel-sv.pub.der \ -+ stunnel-sv.pub.pem \ -+ stunnel-sv.pubkey-pinned -+ -+SRPFILES = \ -+ srp-verifier-conf \ -+ srp-verifier-db -diff --git a/tests/certs/Server-localhost-firstSAN-sv.pem b/tests/certs/Server-localhost-firstSAN-sv.pem -index 3751e7b60..e06863227 100644 ---- a/tests/certs/Server-localhost-firstSAN-sv.pem -+++ b/tests/certs/Server-localhost-firstSAN-sv.pem -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2 --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2 -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,23 +21,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - - [ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -- --[something] --# The key --# the certificate --# some dhparam -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqFG49ghwozY+A - r1DtF5dt5qhhPqyorBPOmespLElz+RJANcR5hA2esCjEn2TjwW0tcRFdSxRhIEsY -diff --git a/tests/certs/Server-localhost-firstSAN-sv.prm b/tests/certs/Server-localhost-firstSAN-sv.prm -index 911f4ce54..1a3889935 100644 ---- a/tests/certs/Server-localhost-firstSAN-sv.prm -+++ b/tests/certs/Server-localhost-firstSAN-sv.prm -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2 --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2 -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,20 +21,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - - [ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -- --[something] --# The key --# the certificate --# some dhparam -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn -diff --git a/tests/certs/Server-localhost-lastSAN-sv.pem b/tests/certs/Server-localhost-lastSAN-sv.pem -index b1cbd4b6b..c3124ff1c 100644 ---- a/tests/certs/Server-localhost-lastSAN-sv.pem -+++ b/tests/certs/Server-localhost-lastSAN-sv.pem -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,22 +21,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIhP5pZDPD3LV0 - iseyu9lp4qmVbV+3JeaCACv1UyHnKK5mtjj9FbGRiFIxKbtz4uCZYpVENVHXVMjS -diff --git a/tests/certs/Server-localhost-lastSAN-sv.prm b/tests/certs/Server-localhost-lastSAN-sv.prm -index c5e72f454..fd2507323 100644 ---- a/tests/certs/Server-localhost-lastSAN-sv.prm -+++ b/tests/certs/Server-localhost-lastSAN-sv.prm -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,19 +21,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn -diff --git a/tests/certs/Server-localhost-sv.pem b/tests/certs/Server-localhost-sv.pem -index 583831f8f..2761de438 100644 ---- a/tests/certs/Server-localhost-sv.pem -+++ b/tests/certs/Server-localhost-sv.pem -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,22 +21,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost - -----BEGIN PRIVATE KEY----- - MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGuAQ91voxoNf3 - 6YhLWl5vb9v0yUt+bCrPNHsquhpxrX94bPceygfQKQNJ5GOGTPZnP70yacu4FecO -diff --git a/tests/certs/Server-localhost-sv.prm b/tests/certs/Server-localhost-sv.prm -index f58710406..54a07e3f3 100644 ---- a/tests/certs/Server-localhost-sv.prm -+++ b/tests/certs/Server-localhost-sv.prm -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,19 +21,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost -diff --git a/tests/certs/Server-localhost.nn-sv.pem b/tests/certs/Server-localhost.nn-sv.pem -index 29dc52ce0..4ce5c1e6b 100644 ---- a/tests/certs/Server-localhost.nn-sv.pem -+++ b/tests/certs/Server-localhost.nn-sv.pem -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost.nn --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost.nn -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,22 +21,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn - -----BEGIN PRIVATE KEY----- - MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCjmuQP4L2TqVqn - Xq2FXtbgmLTpIuBikMPZVzcWXVc9aMrizy9GZxoMrw6JhgEG39bJgBUKQ4VAP9ru -diff --git a/tests/certs/Server-localhost.nn-sv.prm b/tests/certs/Server-localhost.nn-sv.prm -index 5e93bf8b7..376fc3a11 100644 ---- a/tests/certs/Server-localhost.nn-sv.prm -+++ b/tests/certs/Server-localhost.nn-sv.prm -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost.nn --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost.nn -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,19 +21,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost.nn -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost.nn -diff --git a/tests/certs/Server-localhost0h-sv.pem b/tests/certs/Server-localhost0h-sv.pem -index 72f326dfb..9c4c9632a 100644 ---- a/tests/certs/Server-localhost0h-sv.pem -+++ b/tests/certs/Server-localhost0h-sv.pem -@@ -1,12 +1,13 @@ - extensions = x509v3 -+ - [ x509v3 ] --#subjectAltName = DNS:localhost\0h --subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68 --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+#subjectAltName = DNS:localhost\0h -+subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68 -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -21,22 +22,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost - -----BEGIN PRIVATE KEY----- - MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfKZNYgh2iuAcq - so+TDt8VSXIGkxlKLcW9VpJa2vTTmgEc7kdXDp7Y1w3Ezkui8PwH7JHplQj06V3y -diff --git a/tests/certs/Server-localhost0h-sv.prm b/tests/certs/Server-localhost0h-sv.prm -index 439aefb9e..428534176 100644 ---- a/tests/certs/Server-localhost0h-sv.prm -+++ b/tests/certs/Server-localhost0h-sv.prm -@@ -1,12 +1,13 @@ - extensions = x509v3 -+ - [ x509v3 ] --#subjectAltName = DNS:localhost\0h --subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68 --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+#subjectAltName = DNS:localhost\0h -+subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68 -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -21,19 +22,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 1024 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 1024 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost -diff --git a/tests/certs/scripts/genroot.sh b/tests/certs/scripts/genroot.sh -index 17fd30887..86afb1853 100755 ---- a/tests/certs/scripts/genroot.sh -+++ b/tests/certs/scripts/genroot.sh -@@ -1,4 +1,4 @@ --#!/bin/bash -+#!/usr/bin/env bash - #*************************************************************************** - # _ _ ____ _ - # Project ___| | | | _ \| | -@@ -23,67 +23,59 @@ - # - ########################################################################### - -+# exit on first fail -+set -eu -+ - OPENSSL=openssl --if [ -f /usr/local/ssl/bin/openssl ] ; then --OPENSSL=/usr/local/ssl/bin/openssl -+if [ -f /usr/local/ssl/bin/openssl ]; then -+ OPENSSL=/usr/local/ssl/bin/openssl - fi - --USAGE="echo Usage is genroot.sh \" -+command -v "$OPENSSL" -+"$OPENSSL" version -+ -+USAGE='echo Usage is genroot.sh ' - --HOME=`pwd` --cd $HOME -+HOME=$(pwd) -+cd "$HOME" - - KEYSIZE=2048 - DURATION=6000 - # The -sha256 option was introduced in OpenSSL 1.0.1 - DIGESTALGO=-sha256 - --PREFIX=$1 --if [ ".$PREFIX" = . ] ; then -- echo No configuration prefix -- NOTOK=1 -+NOTOK= -+ -+PREFIX="${1:-}" -+if [ -z "$PREFIX" ]; then -+ echo 'No configuration prefix' -+ NOTOK=1 - else -- if [ ! -f $PREFIX-ca.prm ] ; then -- echo No configuration file $PREFIX-ca.prm -- NOTOK=1 -- fi -+ if [ ! -f "$PREFIX-ca.prm" ]; then -+ echo "No configuration file $PREFIX-ca.prm" -+ NOTOK=1 -+ fi - fi - --if [ ".$NOTOK" != . ] ; then -- echo "Sorry, I can't do that for you." -- $USAGE -- exit -+if [ -n "$NOTOK" ]; then -+ echo 'Sorry, I cannot do that for you.' -+ $USAGE -+ exit - fi - --GETSERIAL="\$t = time ;\$d = \$t . substr(\$t+$$ ,-4,4)-1;print \$d" --SERIAL=`/usr/bin/env perl -e "$GETSERIAL"` -- --# exit on first fail --set -e -- --echo SERIAL=$SERIAL PREFIX=$PREFIX DURATION=$DURATION KEYSIZE=$KEYSIZE -- --echo "openssl genrsa -out $PREFIX-ca.key -passout XXX $KEYSIZE" --openssl genrsa -out $PREFIX-ca.key -passout pass:secret $KEYSIZE -- --echo "openssl req -config $PREFIX-ca.prm -new -key $PREFIX-ca.key -out $PREFIX-ca.csr" --$OPENSSL req -config $PREFIX-ca.prm -new -key $PREFIX-ca.key -out $PREFIX-ca.csr -passin pass:secret -- --echo "openssl x509 -set_serial $SERIAL -extfile $PREFIX-ca.prm -days $DURATION -req -signkey $PREFIX-ca.key -in $PREFIX-ca.csr -out $PREFIX-$SERIAL.ca-cacert $DIGESTALGO " -- --$OPENSSL x509 -set_serial $SERIAL -extfile $PREFIX-ca.prm -days $DURATION -req -signkey $PREFIX-ca.key -in $PREFIX-ca.csr -out $PREFIX-$SERIAL-ca.cacert $DIGESTALGO -- --echo "openssl x509 -text -in $PREFIX-$SERIAL-ca.cacert -nameopt multiline > $PREFIX-ca.cacert " --$OPENSSL x509 -text -in $PREFIX-$SERIAL-ca.cacert -nameopt multiline > $PREFIX-ca.cacert -- --echo "openssl x509 -in $PREFIX-ca.cacert -outform der -out $PREFIX-ca.der " --$OPENSSL x509 -in $PREFIX-ca.cacert -outform der -out $PREFIX-ca.der -- --echo "openssl x509 -in $PREFIX-ca.cacert -text -nameopt multiline > $PREFIX-ca.crt " -- --$OPENSSL x509 -in $PREFIX-ca.cacert -text -nameopt multiline > $PREFIX-ca.crt -- --echo "openssl x509 -noout -text -in $PREFIX-ca.cacert -nameopt multiline" --$OPENSSL x509 -noout -text -in $PREFIX-ca.cacert -nameopt multiline -- --#$OPENSSL rsa -in ../keys/$PREFIX-ca.key -text -noout -pubout -+echo "PREFIX=$PREFIX DURATION=$DURATION KEYSIZE=$KEYSIZE" -+ -+set -x -+ -+"$OPENSSL" genrsa -out "$PREFIX-ca.key" -passout fd:0 "$KEYSIZE" < "$PREFIX-ca.cacert" -+"$OPENSSL" x509 -in "$PREFIX-ca.cacert" -outform der -out "$PREFIX-ca.der" -+"$OPENSSL" x509 -in "$PREFIX-ca.cacert" -text -nameopt multiline > "$PREFIX-ca.crt" -+"$OPENSSL" x509 -noout -text -in "$PREFIX-ca.cacert" -nameopt multiline -+# "$OPENSSL" rsa -in "../keys/$PREFIX-ca.key" -text -noout -pubout -diff --git a/tests/certs/scripts/genserv.sh b/tests/certs/scripts/genserv.sh -index 7e0b4429c..73e497836 100755 ---- a/tests/certs/scripts/genserv.sh -+++ b/tests/certs/scripts/genserv.sh -@@ -1,4 +1,4 @@ --#!/bin/bash -+#!/usr/bin/env bash - #*************************************************************************** - # _ _ ____ _ - # Project ___| | | | _ \| | -@@ -23,21 +23,24 @@ - # - ########################################################################### - -+# exit on first fail -+set -eu -+ - OPENSSL=openssl --if [ -f /usr/local/ssl/bin/openssl ] ; then -- OPENSSL=/usr/local/ssl/bin/openssl -+if [ -f /usr/local/ssl/bin/openssl ]; then -+ OPENSSL=/usr/local/ssl/bin/openssl - fi - --USAGE="echo Usage is genserv.sh " -+command -v "$OPENSSL" -+"$OPENSSL" version - --# exit on first fail --set -e -+USAGE='echo Usage is genserv.sh ' - --HOME=`pwd` --cd $HOME -+HOME=$(pwd) -+cd "$HOME" - - KEYSIZE=2048 --DURATION=3000 -+DURATION=300 - # The -sha256 option was introduced in OpenSSL 1.0.1 - DIGESTALGO=-sha256 - -@@ -45,99 +48,86 @@ REQ=YES - P12=NO - DHP=NO - --PREFIX=$1 --if [ ".$PREFIX" = . ] ; then -- echo No configuration prefix -- NOTOK=1 -+NOTOK= -+ -+PREFIX="${1:-}" -+if [ -z "$PREFIX" ]; then -+ echo 'No configuration prefix' -+ NOTOK=1 - else -- if [ ! -f $PREFIX-sv.prm ] ; then -- echo No configuration file $PREFIX-sv.prm -- NOTOK=1 -- fi -+ if [ ! -f "$PREFIX-sv.prm" ]; then -+ echo "No configuration file $PREFIX-sv.prm" -+ NOTOK=1 -+ fi - fi - --CAPREFIX=$2 --if [ ".$CAPREFIX" = . ] ; then -- echo No CA prefix -- NOTOK=1 -+CAPREFIX="${2:-}" -+if [ -z "$CAPREFIX" ]; then -+ echo 'No CA prefix' -+ NOTOK=1 - else -- if [ ! -f $CAPREFIX-ca.cacert ] ; then -- echo No CA certificate file $CAPREFIX-ca.caert -- NOTOK=1 -- fi -- if [ ! -f $CAPREFIX-ca.key ] ; then -- echo No $CAPREFIX key -- NOTOK=1 -- fi -+ if [ ! -f "$CAPREFIX-ca.cacert" ]; then -+ echo "No CA certificate file $CAPREFIX-ca.caert" -+ NOTOK=1 -+ fi -+ if [ ! -f "$CAPREFIX-ca.key" ]; then -+ echo "No $CAPREFIX key" -+ NOTOK=1 -+ fi - fi - --if [ ".$NOTOK" != . ] ; then -- echo "Sorry, I can't do that for you." -- $USAGE -- exit -+if [ -n "$NOTOK" ]; then -+ echo 'Sorry, I cannot do that for you.' -+ $USAGE -+ exit - fi - --if [ ".$SERIAL" = . ] ; then -- GETSERIAL="\$t = time ;\$d = \$t . substr(\$t+$$ ,-4,4)-1;print \$d" -- SERIAL=`/usr/bin/env perl -e "$GETSERIAL"` --fi -+echo "PREFIX=$PREFIX CAPREFIX=$CAPREFIX DURATION=$DURATION KEYSIZE=$KEYSIZE" - --echo SERIAL=$SERIAL PREFIX=$PREFIX CAPREFIX=$CAPREFIX DURATION=$DURATION KEYSIZE=$KEYSIZE -+set -x - --if [ "$DHP." = YES. ] ; then -- echo "openssl dhparam -2 -out $PREFIX-sv.dhp $KEYSIZE" -- $OPENSSL dhparam -2 -out $PREFIX-sv.dhp $KEYSIZE -+if [ "$DHP" = YES ]; then -+ "$OPENSSL" dhparam -2 -out "$PREFIX-sv.dhp" "$KEYSIZE" - fi -- --if [ "$REQ." = YES. ] ; then -- echo "openssl req -config $PREFIX-sv.prm -newkey rsa:$KEYSIZE -keyout $PREFIX-sv.key -out $PREFIX-sv.csr -passout XXX" -- $OPENSSL req -config $PREFIX-sv.prm -newkey rsa:$KEYSIZE -keyout $PREFIX-sv.key -out $PREFIX-sv.csr -passout pass:secret -+if [ "$REQ" = YES ]; then -+ "$OPENSSL" req -config "$PREFIX-sv.prm" -newkey "rsa:$KEYSIZE" -keyout "$PREFIX-sv.key" -out "$PREFIX-sv.csr" -passout fd:0 < $PREFIX-sv.crt " -- --$OPENSSL x509 -set_serial $SERIAL -extfile $PREFIX-sv.prm -days $DURATION -CA $CAPREFIX-ca.cacert -CAkey $CAPREFIX-ca.key -in $PREFIX-sv.csr -req -text -nameopt multiline $DIGESTALGO > $PREFIX-sv.crt -+"$OPENSSL" rsa -in "$PREFIX-sv.key" -out "$PREFIX-sv.key" -passin fd:0 < "$PREFIX-sv.crt" - -- $OPENSSL pkcs12 -export -des3 -out $PREFIX-sv.p12 -caname $CAPREFIX -name $PREFIX -inkey $PREFIX-sv.key -in $PREFIX-sv.crt -certfile $CAPREFIX-ca.crt -+if [ "$P12" = YES ]; then -+ "$OPENSSL" pkcs12 -export -des3 -out "$PREFIX-sv.p12" -caname "$CAPREFIX" -name "$PREFIX" -inkey "$PREFIX-sv.key" -in "$PREFIX-sv.crt" -certfile "$CAPREFIX-ca.crt" - fi - --echo "openssl x509 -noout -text -hash -in $PREFIX-sv.selfcert -nameopt multiline" --$OPENSSL x509 -noout -text -hash -in $PREFIX-sv.crt -nameopt multiline -+"$OPENSSL" x509 -noout -text -hash -in "$PREFIX-sv.crt" -nameopt multiline - - # revoke server cert --touch $CAPREFIX-ca.db --echo 01 > $CAPREFIX-ca.cnt --echo "openssl ca -config $CAPREFIX-ca.cnf -revoke $PREFIX-sv.crt" --$OPENSSL ca -config $CAPREFIX-ca.cnf -revoke $PREFIX-sv.crt -+touch "$CAPREFIX-ca.db" -+echo 01 > "$CAPREFIX-ca.cnt" -+"$OPENSSL" ca -config "$CAPREFIX-ca.cnf" -revoke "$PREFIX-sv.crt" - - # issue CRL --echo "openssl ca -config $CAPREFIX-ca.cnf -gencrl -out $PREFIX-sv.crl" --$OPENSSL ca -config $CAPREFIX-ca.cnf -gencrl -out $PREFIX-sv.crl -+"$OPENSSL" ca -config "$CAPREFIX-ca.cnf" -gencrl -out "$PREFIX-sv.crl" - --echo "openssl x509 -in $PREFIX-sv.crt -outform der -out $PREFIX-sv.der " --$OPENSSL x509 -in $PREFIX-sv.crt -outform der -out $PREFIX-sv.der -+"$OPENSSL" x509 -in "$PREFIX-sv.crt" -outform der -out "$PREFIX-sv.der" - - # all together now --touch $PREFIX-sv.dhp --cat $PREFIX-sv.prm $PREFIX-sv.key $PREFIX-sv.crt $PREFIX-sv.dhp >$PREFIX-sv.pem --chmod o-r $PREFIX-sv.prm -+touch "$PREFIX-sv.dhp" -+cat "$PREFIX-sv.prm" "$PREFIX-sv.key" "$PREFIX-sv.crt" "$PREFIX-sv.dhp" > "$PREFIX-sv.pem" -+chmod o-r "$PREFIX-sv.prm" - --$OPENSSL x509 -in $PREFIX-sv.pem -pubkey -noout | \ --$OPENSSL pkey -pubin -outform der | $OPENSSL dgst -sha256 -binary | \ --$OPENSSL enc -base64 >$PREFIX-sv.pubkey-pinned -+"$OPENSSL" x509 -in "$PREFIX-sv.pem" -pubkey -noout | \ -+"$OPENSSL" pkey -pubin -outform der | "$OPENSSL" dgst -sha256 -binary | \ -+"$OPENSSL" enc -base64 > "$PREFIX-sv.pubkey-pinned" - - echo "$PREFIX-sv.pem done" -diff --git a/tests/certs/stunnel-sv.pem b/tests/certs/stunnel-sv.pem -index b7dd1e879..b273ff761 100644 ---- a/tests/certs/stunnel-sv.pem -+++ b/tests/certs/stunnel-sv.pem -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,22 +21,18 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 12048 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 12048 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrCrAD0Hb+Xs4V - 3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxaorWweFGVYoCAcchOn1lZ -diff --git a/tests/certs/stunnel-sv.prm b/tests/certs/stunnel-sv.prm -index 3803da375..8fd080bd8 100644 ---- a/tests/certs/stunnel-sv.prm -+++ b/tests/certs/stunnel-sv.prm -@@ -1,11 +1,12 @@ - extensions = x509v3 -+ - [ x509v3 ] --subjectAltName = DNS:localhost --keyUsage = keyEncipherment,digitalSignature,keyAgreement --extendedKeyUsage = serverAuth --subjectKeyIdentifier = hash --authorityKeyIdentifier = keyid --basicConstraints = CA:false -+subjectAltName = DNS:localhost -+keyUsage = keyEncipherment,digitalSignature,keyAgreement -+extendedKeyUsage = serverAuth -+subjectKeyIdentifier = hash -+authorityKeyIdentifier = keyid -+basicConstraints = CA:false - authorityInfoAccess = @issuer_info - crlDistributionPoints = @crl_info - -@@ -20,19 +21,15 @@ caIssuers;URI.0 = http://test.curl.se/ca/EdelCurlRoot.cer - URI.0 = http://test.curl.se/ca/EdelCurlRoot.crl - - [ req ] --default_bits = 12048 --distinguished_name = req_DN --default_md = sha256 --string_mask = utf8only --[ req_DN ] --countryName = "Country Name is Northern Nowhere" --countryName_value = NN --organizationName = "Organization Name" --organizationName_value = Edel Curl Arctic Illudium Research Cloud --commonName = "Common Name" --commonName_value = localhost -+default_bits = 12048 -+distinguished_name = req_DN -+default_md = sha256 -+string_mask = utf8only - --[something] --# The key --# the certificate --# some dhparam -+[ req_DN ] -+countryName = "Country Name is Northern Nowhere" -+countryName_value = NN -+organizationName = "Organization Name" -+organizationName_value = Edel Curl Arctic Illudium Research Cloud -+commonName = "Common Name" -+commonName_value = localhost -diff --git a/tests/configurehelp.pm.in b/tests/configurehelp.pm.in -new file mode 100644 -index 000000000..626df2c51 ---- /dev/null -+++ b/tests/configurehelp.pm.in -@@ -0,0 +1,45 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+ -+package configurehelp; -+ -+use strict; -+use warnings; -+use Exporter; -+ -+use vars qw( -+ @ISA -+ @EXPORT_OK -+ $Cpreprocessor -+ ); -+ -+@ISA = qw(Exporter); -+ -+@EXPORT_OK = qw( -+ $Cpreprocessor -+ ); -+ -+$Cpreprocessor = '@CURL_CPP@'; -+ -+1; -diff --git a/tests/data/DISABLED b/tests/data/DISABLED -index be3b8b5d8..8e75067dc 100644 ---- a/tests/data/DISABLED -+++ b/tests/data/DISABLED -@@ -46,11 +46,11 @@ - # fnmatch differences are just too common to make testing them sensible - 1307 - 1316 --# test 1510 causes problems on the CI on github -+# test 1510 causes problems on the CI on GitHub - # example: https://travis-ci.org/curl/curl/builds/81633600 - 1510 - 1512 --# test 1801 causes problems on Mac OS X and github -+# test 1801 causes problems on macOS and GitHub - # https://github.com/curl/curl/issues/380 - 1801 - # test 2086 causes issues on Windows only -@@ -68,12 +68,15 @@ - # 1591, 1943. See https://github.com/hyperium/hyper/issues/2699 for details. - %if hyper - 266 -+477 -+500 - 579 - 587 - # 1021 re-added here due to flakiness - 1021 --1117 -+1060 - 1417 -+1460 - 1533 - 1540 - 1591 -@@ -86,27 +89,6 @@ - 2307 - %endif - 2043 --# The CRL test (313) doesn't work with rustls because rustls doesn't support --# CRLs. --# Tests that rely on connecting to an IP address over TLS don't work because --# rustls doesn't support IP address certificates yet. That's the 400 series of --# tests listed here, plus 1112 and 1272 --%if rustls --313 --400 --401 --403 --404 --406 --407 --408 --409 --987 --988 --989 --1112 --1272 --%endif - # The CRL test doesn't work with wolfSSL - %if wolfssl - 313 -@@ -115,3 +97,18 @@ - %if bearssl - 313 - %endif -+%if WinIDN -+165 -+%endif -+# Windows non-Unicode builds fail to receive Unicode text via the command-line -+%if win32 -+%if !Unicode -+%if libidn2 -+165 -+1560 -+%endif -+1448 -+2046 -+2047 -+%endif -+%endif -diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am -index 68148c1f9..02bf2ae25 100644 ---- a/tests/data/Makefile.am -+++ b/tests/data/Makefile.am -@@ -21,11 +21,255 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --iall: -+all: - install: - test: - --# TESTCASES are taken from Makefile.inc --include Makefile.inc -+# this list is in numerical order -+TESTCASES = test1 test2 test3 test4 test5 test6 test7 test8 test9 \ -+test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \ -+test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \ -+test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \ -+test40 test41 test42 test43 test44 test45 test46 test47 test48 test49 \ -+test50 test51 test52 test53 test54 test55 test56 test57 test58 test59 \ -+test60 test61 test62 test63 test64 test65 test66 test67 test68 test69 \ -+test70 test71 test72 test73 test74 test75 test77 test78 test79 \ -+test80 test81 test82 test83 test84 test85 test86 test87 test88 test89 \ -+test90 test91 test92 test93 test94 test95 test96 test97 test98 test99 \ -+test100 test101 test102 test103 test104 test105 test106 test107 test108 \ -+test109 test110 test111 test112 test113 test114 test115 test116 test117 \ -+test118 test119 test120 test121 test122 test123 test124 test125 test126 \ -+test127 test128 test129 test130 test131 test132 test133 test134 test135 \ -+test136 test137 test138 test139 test140 test141 test142 test143 test144 \ -+test145 test146 test147 test148 test149 test150 test151 test152 test153 \ -+test154 test155 test156 test157 test158 test159 test160 test161 test162 \ -+test163 test164 test165 test166 test167 test168 test169 test170 test171 \ -+test172 test173 test174 test175 test176 test177 test178 test179 test180 \ -+test181 test182 test183 test184 test185 test186 test187 test188 test189 \ -+test190 test191 test192 test193 test194 test195 test196 test197 test198 \ -+test199 test200 test201 test202 test203 test204 test205 test206 test207 \ -+test208 test209 test210 test211 test212 test213 test214 test215 test216 \ -+test217 test218 test219 test220 test221 test222 test223 test224 test225 \ -+test226 test227 test228 test229 test230 test231 test232 test233 test234 \ -+test235 test236 test237 test238 test239 test240 test241 test242 test243 \ -+test244 test245 test246 test247 test248 test249 test250 test251 test252 \ -+test253 test254 test255 test256 test257 test258 test259 test260 test261 \ -+test262 test263 test264 test265 test266 test267 test268 test269 test270 \ -+test271 test272 test273 test274 test275 test276 test277 test278 test279 \ -+test280 test281 test282 test283 test284 test285 test286 test287 test288 \ -+test289 test290 test291 test292 test293 test294 test295 test296 test297 \ -+test298 test299 test300 test301 test302 test303 test304 test305 test306 \ -+test307 test308 test309 test310 test311 test312 test313 test314 test315 \ -+test316 test317 test318 test319 test320 test321 test322 test323 test324 \ -+test325 test326 test327 test328 test329 test330 test331 test332 test333 \ -+test334 test335 test336 test337 test338 test339 test340 test341 test342 \ -+test343 test344 test345 test346 test347 test348 test349 test350 test351 \ -+test352 test353 test354 test355 test356 test357 test358 test359 test360 \ -+test361 test362 test363 test364 test365 test366 test367 test368 test369 \ -+test370 test371 test372 test373 test374 test375 test376 test378 test379 \ -+test380 test381 test383 test384 test385 test386 test387 test388 test389 \ -+test390 test391 test392 test393 test394 test395 test396 test397 test398 \ -+test399 test400 test401 test402 test403 test404 test405 test406 test407 \ -+test408 test409 test410 test411 test412 test413 test414 test415 test416 \ -+test417 test418 test419 test420 test421 test422 test423 test424 test425 \ -+test426 test427 test428 test429 test430 test431 test432 test433 test434 \ -+test435 test436 test437 test438 test439 test440 test441 test442 test443 \ -+test444 test445 test446 test447 test448 test449 test450 test451 test452 \ -+test453 test454 test455 test456 test457 test458 test459 test460 test461 \ -+test462 test463 test467 test468 test469 test470 test471 test472 test473 \ -+test474 test475 test476 test477 \ -+\ -+test490 test491 test492 test493 test494 test495 test496 test497 test498 \ -+test499 test500 test501 test502 test503 test504 test505 test506 test507 \ -+test508 test509 test510 test511 test512 test513 test514 test515 test516 \ -+test517 test518 test519 test520 test521 test522 test523 test524 test525 \ -+test526 test527 test528 test529 test530 test531 test532 test533 test534 \ -+test535 test536 test537 test538 test539 test540 test541 test542 test543 \ -+test544 test545 test546 test547 test548 test549 test550 test551 test552 \ -+test553 test554 test555 test556 test557 test558 test559 test560 test561 \ -+test562 test563 test564 test565 test566 test567 test568 test569 test570 \ -+test571 test572 test573 test574 test575 test576 test577 test578 test579 \ -+test580 test581 test582 test583 test584 test585 test586 test587 test588 \ -+test589 test590 test591 test592 test593 test594 test595 test596 test597 \ -+test598 test599 test600 test601 test602 test603 test604 test605 test606 \ -+test607 test608 test609 test610 test611 test612 test613 test614 test615 \ -+test616 test617 test618 test619 test620 test621 test622 test623 test624 \ -+test625 test626 test627 test628 test629 test630 test631 test632 test633 \ -+test634 test635 test636 test637 test638 test639 test640 test641 test642 \ -+test643 test644 test645 test646 test647 test648 test649 test650 test651 \ -+test652 test653 test654 test655 test656 test658 test659 test660 test661 \ -+test662 test663 test664 test665 test666 test667 test668 test669 test670 \ -+test671 test672 test673 test674 test675 test676 test677 test678 test679 \ -+test680 test681 test682 test683 test684 test685 test686 test687 test688 \ -+test689 test690 test691 test692 \ -+\ -+test700 test701 test702 test703 test704 test705 test706 test707 test708 \ -+test709 test710 test711 test712 test713 test714 test715 test716 test717 \ -+test718 test719 test720 test721 test722 test723 test724 test725 test726 \ -+test727 test728 test729 test730 test731 test732 test733 test734 test735 \ -+test736 test737 test738 test739 test740 test741 test742 \ -+\ -+test780 test781 test782 test783 \ -+\ -+test799 test800 test801 test802 test803 test804 test805 test806 test807 \ -+test808 test809 test810 test811 test812 test813 test814 test815 test816 \ -+test817 test818 test819 test820 test821 test822 test823 test824 test825 \ -+test826 test827 test828 test829 test830 test831 test832 test833 test834 \ -+test835 test836 test837 test838 test839 test840 test841 test842 test843 \ -+test844 test845 test846 test847 test848 test849 test850 test851 test852 \ -+test853 test854 test855 test856 test857 test858 test859 test860 test861 \ -+test862 test863 test864 test865 test866 test867 test868 test869 test870 \ -+test871 test872 test873 test874 test875 test876 test877 test878 test879 \ -+test880 test881 test882 test883 test884 test885 test886 test887 test888 \ -+test889 test890 test891 test892 test893 test894 test895 test896 test897 \ -+test898 test899 test900 test901 test902 test903 test904 test905 test906 \ -+test907 test908 test909 test910 test911 test912 test913 test914 test915 \ -+test916 test917 test918 test919 test920 test921 test922 test923 test924 \ -+test925 test926 test927 test928 test929 test930 test931 test932 test933 \ -+test934 test935 test936 test937 test938 test939 test940 test941 test942 \ -+test943 test944 test945 test946 test947 test948 test949 test950 test951 \ -+test952 test953 test954 test955 test956 test957 test958 test959 test960 \ -+test961 test962 test963 test964 test965 test966 test967 test968 test969 \ -+test970 test971 test972 test973 test974 test975 test976 test977 test978 \ -+test979 test980 test981 test982 test983 test984 test985 test986 test987 \ -+test988 test989 test990 test991 test992 test993 test994 test995 test996 \ -+test997 test998 test999 test1000 test1001 test1002 test1003 test1004 \ -+test1005 test1006 test1007 test1008 test1009 test1010 test1011 test1012 \ -+test1013 test1014 test1015 test1016 test1017 test1018 test1019 test1020 \ -+test1021 test1022 test1023 test1024 test1025 test1026 test1027 test1028 \ -+test1029 test1030 test1031 test1032 test1033 test1034 test1035 test1036 \ -+test1037 test1038 test1039 test1040 test1041 test1042 test1043 test1044 \ -+test1045 test1046 test1047 test1048 test1049 test1050 test1051 test1052 \ -+test1053 test1054 test1055 test1056 test1057 test1058 test1059 test1060 \ -+test1061 test1062 test1063 test1064 test1065 test1066 test1067 test1068 \ -+test1069 test1070 test1071 test1072 test1073 test1074 test1075 test1076 \ -+test1077 test1078 test1079 test1080 test1081 test1082 test1083 test1084 \ -+test1085 test1086 test1087 test1088 test1089 test1090 test1091 test1092 \ -+test1093 test1094 test1095 test1096 test1097 test1098 test1099 test1100 \ -+test1101 test1102 test1103 test1104 test1105 test1106 test1107 test1108 \ -+test1109 test1110 test1111 test1112 test1113 test1114 test1115 test1116 \ -+test1117 test1118 test1119 test1120 test1121 test1122 test1123 test1124 \ -+test1125 test1126 test1127 test1128 test1129 test1130 test1131 test1132 \ -+test1133 test1134 test1135 test1136 test1137 test1138 test1139 test1140 \ -+test1141 test1142 test1143 test1144 test1145 test1146 test1147 test1148 \ -+test1149 test1150 test1151 test1152 test1153 test1154 test1155 test1156 \ -+test1157 test1158 test1159 test1160 test1161 test1162 test1163 test1164 \ -+test1165 test1166 test1167 test1168 test1169 test1170 test1171 test1172 \ -+test1173 test1174 test1175 test1176 test1177 test1178 test1179 test1180 \ -+test1181 test1182 test1183 test1184 test1185 test1186 test1187 test1188 \ -+test1189 test1190 test1190 test1191 test1192 test1193 test1194 test1195 \ -+test1196 test1197 test1198 test1199 test1200 test1201 test1202 test1203 \ -+test1204 test1205 test1206 test1207 test1208 test1209 test1210 test1211 \ -+test1212 test1213 test1214 test1215 test1216 test1217 test1218 test1219 \ -+test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \ -+test1228 test1229 test1230 test1231 test1232 test1233 test1234 test1235 \ -+test1236 test1237 test1238 test1239 test1240 test1241 test1242 test1243 \ -+test1244 test1245 test1246 test1247 test1248 test1249 test1250 test1251 \ -+test1252 test1253 test1254 test1255 test1256 test1257 test1258 test1259 \ -+test1260 test1261 test1262 test1263 test1264 test1265 test1266 test1267 \ -+test1268 test1269 test1270 test1271 test1272 test1273 test1274 test1275 \ -+test1276 test1277 test1278 test1279 test1280 test1281 test1282 test1283 \ -+test1284 test1285 test1286 test1287 test1288 test1289 test1290 test1291 \ -+test1292 test1293 test1294 test1295 test1296 test1297 test1298 test1299 \ -+test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \ -+test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \ -+test1316 test1317 test1318 test1319 test1320 test1321 test1322 test1323 \ -+test1324 test1325 test1326 test1327 test1328 test1329 test1330 test1331 \ -+test1332 test1333 test1334 test1335 test1336 test1337 test1338 test1339 \ -+test1340 test1341 test1342 test1343 test1344 test1345 test1346 test1347 \ -+test1348 test1349 test1350 test1351 test1352 test1353 test1354 test1355 \ -+test1356 test1357 test1358 test1359 test1360 test1361 test1362 test1363 \ -+test1364 test1365 test1366 test1367 test1368 test1369 test1370 test1371 \ -+test1372 test1373 test1374 test1375 test1376 test1377 test1378 test1379 \ -+test1380 test1381 test1382 test1383 test1384 test1385 test1386 test1387 \ -+test1388 test1389 test1390 test1391 test1392 test1393 test1394 test1395 \ -+test1396 test1397 test1398 test1399 test1400 test1401 test1402 test1403 \ -+test1404 test1405 test1406 test1407 test1408 test1409 test1410 test1411 \ -+test1412 test1413 test1414 test1415 test1416 test1417 test1418 test1419 \ -+test1420 test1421 test1422 test1423 test1424 test1425 test1426 test1427 \ -+test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \ -+test1436 test1437 test1438 test1439 test1440 test1441 test1442 test1443 \ -+test1444 test1445 test1446 test1447 test1448 test1449 test1450 test1451 \ -+test1452 test1453 test1454 test1455 test1456 test1457 test1458 test1459 \ -+test1460 test1461 test1462 test1463 test1464 test1465 test1466 test1467 \ -+test1468 test1469 test1470 test1471 test1472 test1473 test1474 test1475 \ -+test1476 test1477 test1478 test1479 test1480 test1481 test1482 test1483 \ -+test1484 test1485 test1486 test1487 test1488 test1489 test1490 test1491 \ -+test1492 \ -+\ -+test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ -+test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ -+test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \ -+test1524 test1525 test1526 test1527 test1528 test1529 test1530 test1531 \ -+test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 \ -+test1540 test1541 test1542 test1543 test1544 test1545 test1546 \ -+\ -+test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \ -+test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \ -+test1566 test1567 test1568 test1569 test1570 \ -+\ -+test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \ -+test1598 \ -+test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \ -+test1608 test1609 test1610 test1611 test1612 test1613 test1614 test1615 \ -+test1616 \ -+test1620 test1621 \ -+\ -+test1630 test1631 test1632 test1633 test1634 test1635 \ -+\ -+test1650 test1651 test1652 test1653 test1654 test1655 test1656 \ -+test1660 test1661 test1662 test1663 \ -+\ -+test1670 test1671 \ -+\ -+test1680 test1681 test1682 test1683 \ -+\ -+test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ -+test1708 test1709 test1710 \ -+\ -+test1800 test1801 \ -+\ -+test1900 test1901 test1903 test1904 test1905 test1906 test1907 \ -+test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \ -+test1916 test1917 test1918 test1919 \ -+\ -+test1933 test1934 test1935 test1936 test1937 test1938 test1939 test1940 \ -+test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \ -+test1955 test1956 test1957 test1958 test1959 test1960 test1964 \ -+test1970 test1971 test1972 test1973 test1974 test1975 test1976 \ -+\ -+test2000 test2001 test2002 test2003 test2004 \ -+\ -+ test2023 \ -+test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ -+test2032 test2033 test2034 test2035 test2037 test2038 test2039 \ -+test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 \ -+test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055 \ -+test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \ -+test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \ -+test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ -+test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ -+\ -+test2100 \ -+\ -+test2200 test2201 test2202 test2203 test2204 test2205 \ -+\ -+test2300 test2301 test2302 test2303 test2304 test2305 test2306 test2307 \ -+test2308 \ -+\ -+test2400 test2401 test2402 test2403 test2404 test2405 test2406 \ -+\ -+test2500 test2501 test2502 test2503 \ -+\ -+test2600 test2601 test2602 test2603 test2604 \ -+\ -+test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \ -+test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \ -+test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \ -+test3024 test3025 test3026 test3027 test3028 test3029 test3030 test3031 \ -+\ -+test3100 test3101 test3102 test3103 \ -+test3200 \ -+test3201 test3202 test3203 test3204 test3205 test3207 - --EXTRA_DIST = $(TESTCASES) DISABLED CMakeLists.txt -+EXTRA_DIST = $(TESTCASES) DISABLED -diff --git a/tests/data/test100 b/tests/data/test100 -index de6a82bda..54d31744b 100644 ---- a/tests/data/test100 -+++ b/tests/data/test100 -@@ -9,8 +9,6 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server - - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT/test-%TESTNUMBER/ - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1000 b/tests/data/test1000 -index fe94010ac..e102a006e 100644 ---- a/tests/data/test1000 -+++ b/tests/data/test1000 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER/ -I - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1003 b/tests/data/test1003 -index 06cfbb61b..4947d1dfb 100644 ---- a/tests/data/test1003 -+++ b/tests/data/test1003 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1004 b/tests/data/test1004 -index d176a1658..33faaafb1 100644 ---- a/tests/data/test1004 -+++ b/tests/data/test1004 -@@ -53,8 +53,5 @@ User-Agent: curl/%VERSION - Accept: */* - - -- --disable -- - - -diff --git a/tests/data/test1005 b/tests/data/test1005 -index 28af85f40..8a036bb60 100644 ---- a/tests/data/test1005 -+++ b/tests/data/test1005 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1006 b/tests/data/test1006 -index 394b5563b..004598ff1 100644 ---- a/tests/data/test1006 -+++ b/tests/data/test1006 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test101 b/tests/data/test101 -index 26824c741..8acbd21f7 100644 ---- a/tests/data/test101 -+++ b/tests/data/test101 -@@ -8,9 +8,7 @@ LIST - - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -22,7 +20,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # Client-side -@@ -40,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/ -P %CLIENTIP - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1010 b/tests/data/test1010 -index d1eee918a..cd0337293 100644 ---- a/tests/data/test1010 -+++ b/tests/data/test1010 -@@ -9,9 +9,8 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -19,11 +18,11 @@ drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT - -r--r--r-- 1 0 1 35 Jul 16 1996 README - lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin - dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev --drwxrwxrwx 2 98 98 512 May 29 16:04 download.html -+drwxrwxrwx 2 98 98 512 May 29 16:04 downthis.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -43,6 +42,9 @@ ftp://%HOSTIP:%FTPPORT//list/this/path/%TESTNUMBER/ ftp://%HOSTIP:%FTPPORT//list - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1013 b/tests/data/test1013 -index d748657b5..87e99cd56 100644 ---- a/tests/data/test1013 -+++ b/tests/data/test1013 -@@ -22,14 +22,14 @@ Compare curl --version with curl-config --protocols - - --version - -- --%SRCDIR/libtest/test%TESTNUMBER.pl ../curl-config %LOGDIR/stdout%TESTNUMBER protocols -- - - - # - # Verify data after the test has been "shot" - -+ -+%SRCDIR/libtest/test%TESTNUMBER.pl ../curl-config %LOGDIR/stdout%TESTNUMBER protocols -+ - - 0 - -diff --git a/tests/data/test1014 b/tests/data/test1014 -index f03ac859d..a8f0a3b1d 100644 ---- a/tests/data/test1014 -+++ b/tests/data/test1014 -@@ -22,14 +22,14 @@ Compare curl --version with curl-config --features - - --version - -- --%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features -- - - - # - # Verify data after the test has been "shot" - -+ -+%SRCDIR/libtest/test1013.pl ../curl-config %LOGDIR/stdout%TESTNUMBER features -+ - - 0 - -diff --git a/tests/data/test102 b/tests/data/test102 -index 7037986f4..151dd8025 100644 ---- a/tests/data/test102 -+++ b/tests/data/test102 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1022 b/tests/data/test1022 -index 6a5dd2180..597dfd05d 100644 ---- a/tests/data/test1022 -+++ b/tests/data/test1022 -@@ -22,14 +22,14 @@ Compare curl --version with curl-config --version - - --version - -- --%SRCDIR/libtest/test%TESTNUMBER.pl ../curl-config %LOGDIR/stdout%TESTNUMBER version -- - - - # - # Verify data after the test has been "shot" - -+ -+%SRCDIR/libtest/test%TESTNUMBER.pl ../curl-config %LOGDIR/stdout%TESTNUMBER version -+ - - 0 - -diff --git a/tests/data/test1023 b/tests/data/test1023 -index 1d8cbfb4c..70e027aa8 100644 ---- a/tests/data/test1023 -+++ b/tests/data/test1023 -@@ -22,14 +22,14 @@ Compare curl --version with curl-config --vernum - - --version - -- --%SRCDIR/libtest/test1022.pl ../curl-config %LOGDIR/stdout%TESTNUMBER vernum -- - - - # - # Verify data after the test has been "shot" - -+ -+%SRCDIR/libtest/test1022.pl ../curl-config %LOGDIR/stdout%TESTNUMBER vernum -+ - - 0 - -diff --git a/tests/data/test1026 b/tests/data/test1026 -index e310e6962..3e4408244 100644 ---- a/tests/data/test1026 -+++ b/tests/data/test1026 -@@ -25,16 +25,16 @@ curl --manual - - --manual - --# Search for these two sentinel lines in the manual output; if they are found, --# then chances are good the entire manual is there. -- --perl -e 'open(IN,$ARGV[0]); my $lines=grep(/(curl\s*-\s*transfer\sa\s*URL)|(AUTHORS)/, ); exit ($lines != 2); # Let this file pass an XML syntax check: ' %LOGDIR/stdout%TESTNUMBER -- - - - # - # Verify data after the test has been "shot" - -+# Search for these two sentinel lines in the manual output; if they are found, -+# then chances are good the entire manual is there. -+ -+%PERL -e 'open(IN,$ARGV[0]); my $lines=grep(/(curl\s*-\s*transfer\sa\s*URL)|(AUTHORS)/, ); exit ($lines != 2); # Let this file pass an XML syntax check: ' %LOGDIR/stdout%TESTNUMBER -+ - - 0 - -diff --git a/tests/data/test1027 b/tests/data/test1027 -index 1d076000b..354df4e40 100644 ---- a/tests/data/test1027 -+++ b/tests/data/test1027 -@@ -22,11 +22,6 @@ curl --help - - --help - --# Search for these two sentinel lines in the help output; if they are found, --# then chances are good the entire help is there. -- --perl -e 'open(IN,$ARGV[0]); my $lines=grep(/(Usage: curl )|(--version\s*Show version)/, ); exit ($lines != 2); # Let this file pass an XML syntax check: ' %LOGDIR/stdout%TESTNUMBER -- - - - # -@@ -35,5 +30,10 @@ perl -e 'open(IN,$ARGV[0]); my $lines=grep(/(Usage: curl )|(--version\s*Show ver - - 0 - -+# Search for these two sentinel lines in the help output; if they are found, -+# then chances are good the entire help is there. -+ -+%PERL -e 'open(IN,$ARGV[0]); my $lines=grep(/(Usage: curl )|(--version\s*Show version)/, ); exit ($lines != 2); # Let this file pass an XML syntax check: ' %LOGDIR/stdout%TESTNUMBER -+ - - -diff --git a/tests/data/test1028 b/tests/data/test1028 -index 3e3659732..9592fb66f 100644 ---- a/tests/data/test1028 -+++ b/tests/data/test1028 -@@ -52,6 +52,9 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER0001 -L - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - GET /%TESTNUMBER0001 HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test103 b/tests/data/test103 -index 52e5645bc..66705310c 100644 ---- a/tests/data/test103 -+++ b/tests/data/test103 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER -P - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1034 b/tests/data/test1034 -index 2a8170487..7e62f6d63 100644 ---- a/tests/data/test1034 -+++ b/tests/data/test1034 -@@ -23,17 +23,15 @@ config file - none - - --idn -+IDN - http - proxy -+codeset-utf8 - - - LC_ALL= - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - HTTP over proxy with malformatted IDN host name - -diff --git a/tests/data/test1035 b/tests/data/test1035 -index 1ace9428d..7c4f55724 100644 ---- a/tests/data/test1035 -+++ b/tests/data/test1035 -@@ -21,22 +21,20 @@ FAILURE - none - - --idn -+IDN - http - proxy -+codeset-utf8 - - - LC_ALL= - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - HTTP over proxy with too long IDN host name - - --http://too-long-IDN-name-cürl-rüles-la-la-la-dee-da-flooby-nooby.local/page/%TESTNUMBER -x %HOSTIP:%NOLISTENPORT -+http://too-long-IDN-name-cürl-rüleß-la-la-la-dee-da-flooby-nooby.local/page/%TESTNUMBER -x %HOSTIP:%NOLISTENPORT - - - -diff --git a/tests/data/test1036 b/tests/data/test1036 -index f777a6ff7..1343a8b7c 100644 ---- a/tests/data/test1036 -+++ b/tests/data/test1036 -@@ -40,6 +40,9 @@ This is the start!! - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1037 b/tests/data/test1037 -index 18c9e5266..967561b3b 100644 ---- a/tests/data/test1037 -+++ b/tests/data/test1037 -@@ -39,6 +39,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -C - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1038 b/tests/data/test1038 -index c2e60a0a4..102d35615 100644 ---- a/tests/data/test1038 -+++ b/tests/data/test1038 -@@ -34,6 +34,9 @@ worx? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1039 b/tests/data/test1039 -index a032c2f9a..342290459 100644 ---- a/tests/data/test1039 -+++ b/tests/data/test1039 -@@ -34,6 +34,9 @@ worx? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test104 b/tests/data/test104 -index 3674f1da0..f8d3d3eac 100644 ---- a/tests/data/test104 -+++ b/tests/data/test104 -@@ -27,6 +27,9 @@ ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER --head - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1044 b/tests/data/test1044 -index 96a4f48c2..a0705d331 100644 ---- a/tests/data/test1044 -+++ b/tests/data/test1044 -@@ -23,7 +23,7 @@ Largefile - # Client-side - - --large_file -+Largefile - - - ftp -@@ -38,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/%TESTNUMBER -I - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1046 b/tests/data/test1046 -index c6bdcbb24..fd05b3d53 100644 ---- a/tests/data/test1046 -+++ b/tests/data/test1046 -@@ -27,7 +27,7 @@ Content-Type: text/plain - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -@@ -36,12 +36,8 @@ http-ipv6 - HTTP-IPv6 GET with numeric localhost --interface - - ---g "http://%HOST6IP:%HTTP6PORT/%TESTNUMBER" --interface ::1 -+-g "http://%HOST6IP:%HTTP6PORT/%TESTNUMBER" --interface %CLIENT6IP-NB - --# --interface doesn't accept an address surrounded by [] so %CLIENT6IP is out -- --perl -e "print 'Test requires default test client host address' if ( '%CLIENT6IP' ne '[::1]' );" -- - - - # -diff --git a/tests/data/test1047 b/tests/data/test1047 -index d54a8494d..b7d17275b 100644 ---- a/tests/data/test1047 -+++ b/tests/data/test1047 -@@ -11,9 +11,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -45,6 +43,9 @@ ftp://%HOSTIP:%FTPPORT/ --interface %CLIENTIP - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1048 b/tests/data/test1048 -index 56f19c4af..5aed75a37 100644 ---- a/tests/data/test1048 -+++ b/tests/data/test1048 -@@ -13,9 +13,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -27,14 +25,14 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -43,17 +41,16 @@ ftp-ipv6 - FTP-IPv6 dir list PASV with localhost --interface - - ---g "ftp://%HOST6IP:%FTP6PORT/" --interface ::1 -+-g "ftp://%HOST6IP:%FTP6PORT/" --interface %CLIENT6IP-NB - --# --interface doesn't accept an address surrounded by [] so %CLIENT6IP is out -- --perl -e "print 'Test requires default test client host address' if ( '%CLIENT6IP' ne '[::1]' );" -- - - - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test105 b/tests/data/test105 -index 2a26ac7ec..7f3052990 100644 ---- a/tests/data/test105 -+++ b/tests/data/test105 -@@ -37,6 +37,9 @@ ftp://userdude:passfellow@%HOSTIP:%FTPPORT/%TESTNUMBER --use-ascii - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER userdude - PASS passfellow -diff --git a/tests/data/test1050 b/tests/data/test1050 -index ff179c637..0f8267f95 100644 ---- a/tests/data/test1050 -+++ b/tests/data/test1050 -@@ -2,6 +2,7 @@ - # Similar to test 253 - - -+FTP - FTP-ipv6 - IPv6 - EPRT -@@ -10,9 +11,7 @@ EPRT - - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,13 +23,13 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -39,16 +38,15 @@ ftp-ipv6 - FTP-IPv6 dir list, EPRT with specified IP - - ---g "ftp://%HOST6IP:%FTP6PORT/" -P ::1 -+-g "ftp://%HOST6IP:%FTP6PORT/" -P %CLIENT6IP-NB - --# --interface doesn't accept an address surrounded by [] so %CLIENT6IP is out -- --perl -e "print 'Test requires default test client host address' if ( '%CLIENT6IP' ne '[::1]' );" -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of EPRT that curl can send - - s/^(EPRT \|2\|::1\|)(.*)/$1/ -diff --git a/tests/data/test1055 b/tests/data/test1055 -index 2d1c604b4..0624a969a 100644 ---- a/tests/data/test1055 -+++ b/tests/data/test1055 -@@ -54,6 +54,9 @@ the - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - PUT /%TESTNUMBER HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test1056 b/tests/data/test1056 -index 40879662a..7ecc34982 100644 ---- a/tests/data/test1056 -+++ b/tests/data/test1056 -@@ -48,7 +48,7 @@ body - # test there. This feature doesn't work on msys or Cygwin, so use a precheck - # to skip those. - --ipv6 -+IPv6 - !win32 - - -@@ -62,7 +62,7 @@ HTTP follow redirect from IPv4 to IPv6 with scope - http://%HOSTIP:%HTTPPORT/we/are/all/twits/%TESTNUMBER -L - - --perl -e "print 'Test is not supported on the Windows kernel' if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin');" -+%PERL -e "print 'Test is not supported on the Windows kernel' if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin');" - - - -diff --git a/tests/data/test1057 b/tests/data/test1057 -index a7cb3bc61..e211dd7da 100644 ---- a/tests/data/test1057 -+++ b/tests/data/test1057 -@@ -36,6 +36,9 @@ FTP retrieve a byte-range relative to end of file - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test106 b/tests/data/test106 -index b5e1e6929..2fec63478 100644 ---- a/tests/data/test106 -+++ b/tests/data/test106 -@@ -35,6 +35,9 @@ FTP GET with type=A style ASCII URL using %20 codes - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1062 b/tests/data/test1062 -index 31a27a947..36b726af8 100644 ---- a/tests/data/test1062 -+++ b/tests/data/test1062 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1063 b/tests/data/test1063 -index fcbc4b883..449263ef6 100644 ---- a/tests/data/test1063 -+++ b/tests/data/test1063 -@@ -20,7 +20,7 @@ none - - - file --large_file -+Largefile - - - Invalid large X- range on a file:// -diff --git a/tests/data/test107 b/tests/data/test107 -index a741b7667..a92a635f8 100644 ---- a/tests/data/test107 -+++ b/tests/data/test107 -@@ -30,6 +30,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - data - to -diff --git a/tests/data/test108 b/tests/data/test108 -index 20ef6577e..ceea4d4b2 100644 ---- a/tests/data/test108 -+++ b/tests/data/test108 -@@ -31,6 +31,9 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1082 b/tests/data/test1082 -index 606df1c86..7d26323a7 100644 ---- a/tests/data/test1082 -+++ b/tests/data/test1082 -@@ -35,7 +35,7 @@ HTTP GET with localhost --interface - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -4 --interface 127.0.0.1 - - --perl -e "print 'Test requires default test client host address' if ( '%CLIENTIP' ne '127.0.0.1' );" -+%PERL -e "print 'Test requires default test client host address' if ( '%CLIENTIP' ne '127.0.0.1' );" - - - -diff --git a/tests/data/test1083 b/tests/data/test1083 -index 8728d6183..b82e308fc 100644 ---- a/tests/data/test1083 -+++ b/tests/data/test1083 -@@ -27,7 +27,7 @@ Content-Type: text/plain - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -@@ -39,7 +39,7 @@ HTTP-IPv6 GET with ip6-localhost --interface - -g "http://%HOST6IP:%HTTP6PORT/%TESTNUMBER" --interface ip6-localhost - - --perl -e "if ('%CLIENT6IP' ne '[::1]') {print 'Test requires default test client host address';} else {exec './server/resolve --ipv6 ip6-localhost'; print 'Cannot run precheck resolve';}" -+%PERL -e "if ('%CLIENT6IP' ne '[::1]') {print 'Test requires default test client host address';} else {exec './server/resolve --ipv6 ip6-localhost'; print 'Cannot run precheck resolve';}" - - - -diff --git a/tests/data/test1085 b/tests/data/test1085 -index b63b0f033..55eb00e06 100644 ---- a/tests/data/test1085 -+++ b/tests/data/test1085 -@@ -20,7 +20,7 @@ non-existing host - - - http --ipv6 -+IPv6 - - - none -diff --git a/tests/data/test1086 b/tests/data/test1086 -index 0b4b875d9..ae5e7a093 100644 ---- a/tests/data/test1086 -+++ b/tests/data/test1086 -@@ -6,7 +6,7 @@ EPSV - RETR - timeout - FAILURE --SLOWDOWN -+SLOWDOWNDATA - flaky - timing-dependent - -@@ -14,10 +14,8 @@ timing-dependent - - # Server-side - --# Overload some standard FTP responses to make them shorter and faster --# to avoid wasting time waiting for the data phase to start - --SLOWDOWN -+SLOWDOWNDATA - REPLY welcome 220 Hey - REPLY USER 331 OK - REPLY PASS 230 OK -@@ -90,7 +88,7 @@ ftp - FTP download with strict timeout and slow data transfer - - --ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -m 7 -+ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -m 5 - - - -diff --git a/tests/data/test109 b/tests/data/test109 -index d466437f2..63d1bc6b6 100644 ---- a/tests/data/test109 -+++ b/tests/data/test109 -@@ -31,6 +31,9 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1091 b/tests/data/test1091 -index 445d31655..b5006c6bc 100644 ---- a/tests/data/test1091 -+++ b/tests/data/test1091 -@@ -30,6 +30,9 @@ FTP URL with type=i - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1096 b/tests/data/test1096 -index e7b163924..f8eb1d4fb 100644 ---- a/tests/data/test1096 -+++ b/tests/data/test1096 -@@ -30,6 +30,9 @@ ftp://%HOSTIP:%FTPPORT/dir/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/dir/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 78 - -diff --git a/tests/data/test110 b/tests/data/test110 -index e53fcd137..c3c3d04bf 100644 ---- a/tests/data/test110 -+++ b/tests/data/test110 -@@ -36,6 +36,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -C 20 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1100 b/tests/data/test1100 -index 1148a79f7..13eaeb317 100644 ---- a/tests/data/test1100 -+++ b/tests/data/test1100 -@@ -65,7 +65,7 @@ This is the final page ! - NTLM - SSL - !SSPI --debug -+Debug - - - http -@@ -73,18 +73,9 @@ http - - HTTP POST with NTLM authorization and following a 302 redirect - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -u testuser:testpass --ntlm -L -d "stuff to send away" - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test1102 b/tests/data/test1102 -index 16994d953..12822b95a 100644 ---- a/tests/data/test1102 -+++ b/tests/data/test1102 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1103 b/tests/data/test1103 -index a53b504bd..2ceb89de0 100644 ---- a/tests/data/test1103 -+++ b/tests/data/test1103 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1105 b/tests/data/test1105 -index afe621bb0..68922dc77 100644 ---- a/tests/data/test1105 -+++ b/tests/data/test1105 -@@ -37,11 +37,9 @@ HTTP with cookie parser and header recording - - "http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER?parm1=this*that/other/thing&parm2=foobar/%TESTNUMBER" -c %LOGDIR/cookie%TESTNUMBER.txt -d "userid=myname&password=mypassword" - -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - cookies -+local-http - - - -diff --git a/tests/data/test1107 b/tests/data/test1107 -index 8b31c76f8..de8b7d76e 100644 ---- a/tests/data/test1107 -+++ b/tests/data/test1107 -@@ -38,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --ftp-pret - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test111 b/tests/data/test111 -index a46f7aef1..a7cd3c3d2 100644 ---- a/tests/data/test111 -+++ b/tests/data/test111 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -C 2000 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 36 - -diff --git a/tests/data/test1112 b/tests/data/test1112 -index b0a610660..5e03509b0 100644 ---- a/tests/data/test1112 -+++ b/tests/data/test1112 -@@ -7,17 +7,15 @@ EPSV - RETR - timeout - FAILURE --SLOWDOWN -+SLOWDOWNDATA - timing-dependent - - - - # Server-side - --# Overload some standard FTP responses to make them shorter and faster --# to avoid wasting time waiting for the data phase to start - --SLOWDOWN -+SLOWDOWNDATA - REPLY welcome 220 Hey - REPLY USER 331 OK - REPLY PASS 230 OK -@@ -93,7 +91,7 @@ ftps - FTPS download with strict timeout and slow data transfer - - ---k --ftp-ssl-control ftps://%HOSTIP:%FTPSPORT/%TESTNUMBER -m 16 -+-k --ftp-ssl-control ftps://%HOSTIP:%FTPSPORT/%TESTNUMBER -m 5 - - - -diff --git a/tests/data/test1113 b/tests/data/test1113 -index 8d10975ea..c0e1230c3 100644 ---- a/tests/data/test1113 -+++ b/tests/data/test1113 -@@ -36,6 +36,9 @@ FTP wildcard download - changed fnmatch, 2x perform (DOS LIST response) - ############################################ - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 0 - -diff --git a/tests/data/test112 b/tests/data/test112 -index 41bbc025d..231f3452f 100644 ---- a/tests/data/test112 -+++ b/tests/data/test112 -@@ -31,6 +31,9 @@ worx? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1135 b/tests/data/test1135 -index de028a0c9..e1e74752a 100644 ---- a/tests/data/test1135 -+++ b/tests/data/test1135 -@@ -109,6 +109,7 @@ curl_multi_assign - curl_multi_get_handles - curl_pushheader_bynum - curl_pushheader_byname -+curl_multi_waitfds - curl_easy_option_by_name - curl_easy_option_by_id - curl_easy_option_next -diff --git a/tests/data/test1137 b/tests/data/test1137 -index cb20aee31..4e8f24f09 100644 ---- a/tests/data/test1137 -+++ b/tests/data/test1137 -@@ -38,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --ignore-content-length - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1145 b/tests/data/test1145 -index 570197ee9..1a02c031d 100644 ---- a/tests/data/test1145 -+++ b/tests/data/test1145 -@@ -18,6 +18,8 @@ file:// bad host - - # This command should not succeed since we only accept - # file:/// file://localhost/ file://127.0.0.1/ -+# Pass %PWD instead of %FILE_PWD to trigger the expected -+# error code with native Windows curl. - - file://bad-host%PWD/%LOGDIR/test%TESTNUMBER.txt - -diff --git a/tests/data/test1149 b/tests/data/test1149 -index 7686ef10b..4b3ba376e 100644 ---- a/tests/data/test1149 -+++ b/tests/data/test1149 -@@ -10,9 +10,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -44,6 +42,9 @@ ftp://%HOSTIP:%FTPPORT/list/this/path/%TESTNUMBER/ --ftp-method multicwd --next - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test115 b/tests/data/test115 -index 22f75c0b6..e4da7ea1f 100644 ---- a/tests/data/test115 -+++ b/tests/data/test115 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 13 - -diff --git a/tests/data/test1152 b/tests/data/test1152 -index 490fde3b7..6052b70b5 100644 ---- a/tests/data/test1152 -+++ b/tests/data/test1152 -@@ -13,8 +13,6 @@ LIST - REPLY PWD 257 "just one - - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server - - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . -@@ -47,6 +45,9 @@ ftp://%HOSTIP:%FTPPORT/test-%TESTNUMBER/ - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1153 b/tests/data/test1153 -index 36c76693a..56ed84005 100644 ---- a/tests/data/test1153 -+++ b/tests/data/test1153 -@@ -13,8 +13,6 @@ LIST - REPLY PWD 257 "/""hello""" - - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server - - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . -@@ -47,6 +45,9 @@ ftp://%HOSTIP:%FTPPORT/test-%TESTNUMBER/ - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1158 b/tests/data/test1158 -index 1a29bd84b..f3cce4496 100644 ---- a/tests/data/test1158 -+++ b/tests/data/test1158 -@@ -32,7 +32,7 @@ HTTP RFC1867-type formposting with filename containing '"' - http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER -F "file=@\"%LOGDIR/test%TESTNUMBER\\\".txt\";type=mo/foo;filename=\"test%TESTNUMBER\\\".txt\"" -F 'file2=@"%LOGDIR/test%TESTNUMBER\".txt"' -F 'file3=@"%LOGDIR/test%TESTNUMBER\".txt";type=m/f,"%LOGDIR/test%TESTNUMBER\".txt"' - - --perl -e "print 'Test requires a system supporting double quotes in file names' if ($^O eq 'msys');" -+%PERL -e "print 'Test requires a system supporting double quotes in file names' if ($^O eq 'msys');" - - # We create this file before the command is invoked! - -diff --git a/tests/data/test116 b/tests/data/test116 -index 37aed2ceb..cab67ad57 100644 ---- a/tests/data/test116 -+++ b/tests/data/test116 -@@ -23,7 +23,7 @@ ftp - - # EPRT is only sent when IPv6 is enabled - --ipv6 -+IPv6 - - - FTP download, failed PORT -@@ -35,6 +35,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -P 1.2.3.4 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 30 - -diff --git a/tests/data/test1162 b/tests/data/test1162 -index b6b394139..5aa706b7f 100644 ---- a/tests/data/test1162 -+++ b/tests/data/test1162 -@@ -37,6 +37,9 @@ MSYS2_ARG_CONV_EXCL=ftp:// - - - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1163 b/tests/data/test1163 -index a109b511b..09ede0cb8 100644 ---- a/tests/data/test1163 -+++ b/tests/data/test1163 -@@ -33,6 +33,9 @@ FTP wildcard with pattern ending with an open-bracket - - - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test117 b/tests/data/test117 -index 3bd5cb57f..c292af730 100644 ---- a/tests/data/test117 -+++ b/tests/data/test117 -@@ -28,6 +28,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 17 - -diff --git a/tests/data/test1173 b/tests/data/test1173 -index ff786c44b..89b0cb5a7 100644 ---- a/tests/data/test1173 -+++ b/tests/data/test1173 -@@ -15,7 +15,7 @@ none - - - --Man page syntax checks -+Manpage syntax checks - - - -diff --git a/tests/data/test118 b/tests/data/test118 -index 9b5b8708e..de7012140 100644 ---- a/tests/data/test118 -+++ b/tests/data/test118 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 19 - -diff --git a/tests/data/test1182 b/tests/data/test1182 -index d1b8fb07b..118b967b3 100644 ---- a/tests/data/test1182 -+++ b/tests/data/test1182 -@@ -21,16 +21,15 @@ Verify that runtests.pl accepts an exclude file with the -E option - - mkdir %LOGDIR/data ; mkdir %LOGDIR/log; cp %SRCDIR/data/test1 %LOGDIR/data; echo 'test:1:Test should not run for unit test %TESTNUMBER' > %LOGDIR/test%TESTNUMBER-exclude-file - -- --grep -q "Test should not run for unit test %TESTNUMBER" %LOGDIR/stdout%TESTNUMBER -- -- - - - - - 1 - -+ -+grep -q "Test should not run for unit test %TESTNUMBER" %LOGDIR/stdout%TESTNUMBER -+ - - - -diff --git a/tests/data/test1185 b/tests/data/test1185 -index 94c3be10c..c3133aa23 100644 ---- a/tests/data/test1185 -+++ b/tests/data/test1185 -@@ -72,10 +72,12 @@ void startfunc(int a, int b) { - - int a = sizeof int; - int a = snprintf(buffer, sizeof(buffer), "%d", 99); -+ int moo = hej?wrong:a>b; -+ int moo2 = wrong2:(a)>(b); - - if(a) b++; - -- // CPP comment? -+ // CPP comment ? - - /* comment doesn't end - -@@ -163,11 +165,35 @@ void startfunc(int a, int b) { - ./%LOGDIR/code1185.c:53:10: warning: use of snprintf is banned (SNPRINTF) - int a = snprintf(buffer, sizeof(buffer), "%d", 99); - ^ --./%LOGDIR/code1185.c:55:7: warning: conditional block on the same line (ONELINECONDITION) -+./%LOGDIR/code1185.c:54:21: warning: missing space before colon (NOSPACEC) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:54:22: warning: missing space after colon (NOSPACEC) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:54:15: warning: missing space before question mark (NOSPACEQ) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:54:16: warning: missing space after question mark (NOSPACEQ) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:54:23: warning: missing space before less or greater than (NOSPACETHAN) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:54:23: warning: missing space after less or greater than (NOSPACETHAN) -+ int moo = hej?wrong:a>b; -+ ^ -+./%LOGDIR/code1185.c:55:23: warning: missing space before less or greater than (NOSPACETHAN) -+ int moo2 = wrong2:(a)>(b); -+ ^ -+./%LOGDIR/code1185.c:55:23: warning: missing space after less or greater than (NOSPACETHAN) -+ int moo2 = wrong2:(a)>(b); -+ ^ -+./%LOGDIR/code1185.c:57:7: warning: conditional block on the same line (ONELINECONDITION) - if(a) b++; - ^ --./%LOGDIR/code1185.c:57:2: warning: // comment (CPPCOMMENTS) -- // CPP comment? -+./%LOGDIR/code1185.c:59:2: warning: // comment (CPPCOMMENTS) -+ // CPP comment ? - ^ - ./%LOGDIR/code1185.c:1:1: error: Missing copyright statement (COPYRIGHT) - -@@ -175,7 +201,7 @@ void startfunc(int a, int b) { - ./%LOGDIR/code1185.c:1:1: error: Missing closing comment (OPENCOMMENT) - - ^ --checksrc: 0 errors and 30 warnings -+checksrc: 0 errors and 38 warnings - - - 5 -diff --git a/tests/data/test1186 b/tests/data/test1186 -index 35be0e10d..5e528dc43 100644 ---- a/tests/data/test1186 -+++ b/tests/data/test1186 -@@ -32,7 +32,7 @@ Multipart formposting with backslash-escaping filename containing '"' - http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER --form-escape -F "file=@\"%LOGDIR/test%TESTNUMBER\\\".txt\";type=mo/foo;filename=\"test%TESTNUMBER\\\".txt\"" -F 'file2=@"%LOGDIR/test%TESTNUMBER\".txt"' -F 'file3=@"%LOGDIR/test%TESTNUMBER\".txt";type=m/f,"%LOGDIR/test%TESTNUMBER\".txt"' - - --perl -e "print 'Test requires a system supporting double quotes in file names' if ($^O eq 'msys');" -+%PERL -e "print 'Test requires a system supporting double quotes in file names' if ($^O eq 'msys');" - - # We create this file before the command is invoked! - -diff --git a/tests/data/test119 b/tests/data/test119 -index 4426def0b..2b36051f9 100644 ---- a/tests/data/test119 -+++ b/tests/data/test119 -@@ -30,6 +30,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -P - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 19 - -diff --git a/tests/data/test120 b/tests/data/test120 -index 64628b659..6e285b433 100644 ---- a/tests/data/test120 -+++ b/tests/data/test120 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -Q "-DELE file" - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1201 b/tests/data/test1201 -index 296e7fa6a..f4c1a4838 100644 ---- a/tests/data/test1201 -+++ b/tests/data/test1201 -@@ -25,7 +25,7 @@ gopher - Gopher selector - - --gopher://%HOSTIP:%GOPHERPORT/1/selector/SELECTOR/%TESTNUMBER? -+gopher://%HOSTIP:%GOPHERPORT/1/selector/SELECTOR/%TESTNUMBER - - - -@@ -33,7 +33,7 @@ gopher://%HOSTIP:%GOPHERPORT/1/selector/SELECTOR/%TESTNUMBER? - # Verify data after the test has been "shot" - - --/selector/SELECTOR/%TESTNUMBER? -+/selector/SELECTOR/%TESTNUMBER - - - -diff --git a/tests/data/test1203 b/tests/data/test1203 -index b4c70e9cb..267fc15cb 100644 ---- a/tests/data/test1203 -+++ b/tests/data/test1203 -@@ -20,7 +20,7 @@ iMenu results error.host 1 - # Client-side - - --ipv6 -+IPv6 - - - gopher-ipv6 -diff --git a/tests/data/test1206 b/tests/data/test1206 -index 228df4adb..6abb0c596 100644 ---- a/tests/data/test1206 -+++ b/tests/data/test1206 -@@ -33,6 +33,9 @@ FTP PORT and 425 on download - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^EPRT \|1\|(.*)/EPRT \|1\|/ - -diff --git a/tests/data/test1207 b/tests/data/test1207 -index 612c42b0d..e192e425e 100644 ---- a/tests/data/test1207 -+++ b/tests/data/test1207 -@@ -33,6 +33,9 @@ FTP PORT and 421 on download - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^EPRT \|1\|(.*)/EPRT \|1\|/ - -diff --git a/tests/data/test121 b/tests/data/test121 -index 3625d0e3e..d9dfe2794 100644 ---- a/tests/data/test121 -+++ b/tests/data/test121 -@@ -35,6 +35,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -Q "-DELE after_transfer" -Q "DELE before_tra - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1210 b/tests/data/test1210 -index 4a07147f9..09f830c72 100644 ---- a/tests/data/test1210 -+++ b/tests/data/test1210 -@@ -24,22 +24,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -J without Content-Disposition - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER?junk -J -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER?junk -J -O --output-dir %LOGDIR - - - -diff --git a/tests/data/test1217 b/tests/data/test1217 -index 691c88e73..47059b247 100644 ---- a/tests/data/test1217 -+++ b/tests/data/test1217 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/get/file/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/get/file/agai - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1219 b/tests/data/test1219 -index 454654399..b28077dce 100644 ---- a/tests/data/test1219 -+++ b/tests/data/test1219 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - PWD - EPSV -diff --git a/tests/data/test122 b/tests/data/test122 -index 1f007c1ce..0566b2407 100644 ---- a/tests/data/test122 -+++ b/tests/data/test122 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -C 5 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1224 b/tests/data/test1224 -index 64ba4482c..61036cd08 100644 ---- a/tests/data/test1224 -+++ b/tests/data/test1224 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT//%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1225 b/tests/data/test1225 -index b20363c3e..39abfcb91 100644 ---- a/tests/data/test1225 -+++ b/tests/data/test1225 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT//foo/%TESTNUMBER ftp://%HOSTIP:%FTPPORT//foo/bar/%TESTNUM - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1226 b/tests/data/test1226 -index 08e706b9b..4ae0e6aff 100644 ---- a/tests/data/test1226 -+++ b/tests/data/test1226 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT//%TESTNUMBER --ftp-method singlecwd - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1227 b/tests/data/test1227 -index 30477a46a..f8246fa46 100644 ---- a/tests/data/test1227 -+++ b/tests/data/test1227 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT//%TESTNUMBER --ftp-method nocwd - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test123 b/tests/data/test123 -index 8ccd69cf6..1d29c8668 100644 ---- a/tests/data/test123 -+++ b/tests/data/test123 -@@ -28,6 +28,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER -C 51 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1230 b/tests/data/test1230 -index 5cdf1643f..fbcff6039 100644 ---- a/tests/data/test1230 -+++ b/tests/data/test1230 -@@ -42,7 +42,7 @@ mooooooo - # Client-side - - --ipv6 -+IPv6 - proxy - - -diff --git a/tests/data/test1233 b/tests/data/test1233 -index 79e641d36..0ca5eed97 100644 ---- a/tests/data/test1233 -+++ b/tests/data/test1233 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test124 b/tests/data/test124 -index d2717949c..2dfc96bb8 100644 ---- a/tests/data/test124 -+++ b/tests/data/test124 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test125 b/tests/data/test125 -index 8de97c14e..a615d092f 100644 ---- a/tests/data/test125 -+++ b/tests/data/test125 -@@ -27,6 +27,9 @@ ftp://%HOSTIP:%FTPPORT/path/to/file/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 9 - -diff --git a/tests/data/test126 b/tests/data/test126 -index b830fc778..285618f11 100644 ---- a/tests/data/test126 -+++ b/tests/data/test126 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/lululul/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1262 b/tests/data/test1262 -index 0a7046ce9..2cb5d8857 100644 ---- a/tests/data/test1262 -+++ b/tests/data/test1262 -@@ -28,6 +28,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/%TESTNUMBER -z "-1 jan 2001" - - - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1268 b/tests/data/test1268 -index 05fe9d8e7..15b15b56e 100644 ---- a/tests/data/test1268 -+++ b/tests/data/test1268 -@@ -17,10 +17,10 @@ warning - none - - --unix-sockets -+UnixSockets - - --file name argument looks like a flag -+filename argument looks like a flag - - - --stderr %LOGDIR/moo%TESTNUMBER --unix-socket -k hej://moo -@@ -29,7 +29,7 @@ file name argument looks like a flag - - - --Warning: The file name argument '-k' looks like a flag. -+Warning: The filename argument '-k' looks like a flag. - curl: (1) Protocol "hej" not supported - - -diff --git a/tests/data/test127 b/tests/data/test127 -index ebf122d01..6871e0dc4 100644 ---- a/tests/data/test127 -+++ b/tests/data/test127 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/path/to/file/%TESTNUMBER --disable-epsv - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1279 b/tests/data/test1279 -index 041f5449b..4b9ce2f19 100644 ---- a/tests/data/test1279 -+++ b/tests/data/test1279 -@@ -24,7 +24,7 @@ Verify libcurl.def against CURL_EXTERN declarations - - - -- -+ - - - -diff --git a/tests/data/test128 b/tests/data/test128 -index d1a5d2acf..d46f454ef 100644 ---- a/tests/data/test128 -+++ b/tests/data/test128 -@@ -24,7 +24,7 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER --crlf - - - file --with unix newlines -+with Unix newlines - meant to be - converted - with -@@ -35,6 +35,9 @@ the - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -46,7 +49,7 @@ QUIT - - - file --with unix newlines -+with Unix newlines - meant to be - converted - with -diff --git a/tests/data/test1291 b/tests/data/test1291 -index ea9a0c6ab..30ea21ac8 100644 ---- a/tests/data/test1291 -+++ b/tests/data/test1291 -@@ -31,7 +31,7 @@ XXXXXXXx - - # generate the config file - --perl -e 'for(1 .. 1000) { printf("upload-file=%LOGDIR/upload-this\nurl=htttttp://non-existing-host.haxx.se/upload/%TESTNUMBER\n", $_);}' > %LOGDIR/cmd%TESTNUMBER; -+%PERL -e 'for(1 .. 1000) { printf("upload-file=%LOGDIR/upload-this\nurl=htttttp://non-existing-host.haxx.se/upload/%TESTNUMBER\n", $_);}' > %LOGDIR/cmd%TESTNUMBER; - - - -diff --git a/tests/data/test1294 b/tests/data/test1294 -index 396f8a173..b16ecb142 100644 ---- a/tests/data/test1294 -+++ b/tests/data/test1294 -@@ -30,7 +30,7 @@ Funny-head: yesyes - - # hyper doesn't support the added crazy header - --debug -+Debug - !hyper - - -diff --git a/tests/data/test1295 b/tests/data/test1295 -index e3692f5d6..5c963cae4 100644 ---- a/tests/data/test1295 -+++ b/tests/data/test1295 -@@ -29,7 +29,7 @@ Funny-head: yesyes - # Client-side - - --debug -+Debug - - - http -diff --git a/tests/data/test1296 b/tests/data/test1296 -index 20dc26570..65fbdb2db 100644 ---- a/tests/data/test1296 -+++ b/tests/data/test1296 -@@ -51,4 +51,3 @@ Accept: */* - - - -- -diff --git a/tests/data/test130 b/tests/data/test130 -index d6fed3367..a0673dd8f 100644 ---- a/tests/data/test130 -+++ b/tests/data/test130 -@@ -10,9 +10,8 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -51,6 +50,9 @@ default login userdef password passwddef - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER user1 - PASS passwd1 -diff --git a/tests/data/test131 b/tests/data/test131 -index c48931175..0511520f7 100644 ---- a/tests/data/test131 -+++ b/tests/data/test131 -@@ -10,10 +10,7 @@ netrc - # - # Server-side - --# --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -50,6 +47,9 @@ machine %HOSTIP login user2 password passwd2 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER user2 - PASS passwd2 -diff --git a/tests/data/test1310 b/tests/data/test1310 -index 12fdbb158..49bb0d36d 100644 ---- a/tests/data/test1310 -+++ b/tests/data/test1310 -@@ -3,122 +3,61 @@ - - HTTP - HTTP GET --HTTP NTLM auth -+-J -+--show-headers - - --# Server-side -- -- -- -- -- --HTTP/1.1 401 Now gimme that second request of crap --Server: Microsoft-IIS/5.0 --Content-Type: text/html; charset=iso-8859-1 --Content-Length: 34 --WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== -- --This is not the real page either! -- -- --# This is supposed to be returned when the server gets the second --# Authorization: NTLM line passed-in from the client -- --HTTP/1.1 200 Things are fine in server land swsclose --Server: Microsoft-IIS/5.0 --Content-Type: text/html; charset=iso-8859-1 --Content-Length: 32 -- --Finally, this is the real page! -- -- -- --HTTP/1.1 401 Now gimme that second request of crap --Server: Microsoft-IIS/5.0 --Content-Type: text/html; charset=iso-8859-1 --Content-Length: 34 --WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== -- --HTTP/1.1 200 Things are fine in server land swsclose --Server: Microsoft-IIS/5.0 --Content-Type: text/html; charset=iso-8859-1 --Content-Length: 32 -- --Finally, this is the real page! -- - -+# -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 6 -+Connection: close -+Content-Disposition: inline; filename="name%TESTNUMBER" -+Content-Type: text/html -+ -+12345 -+ - - -+# - # Client-side - -- --NTLM_WB --debug -- - - http - - --HTTP with NTLM delegation to winbind helper -+HTTP GET with -J + --show-headers - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so --# set path to fake_auth instead of real ntlm_auth to generate NTLM type1 and type 3 messages --CURL_NTLM_WB_FILE=%PWD/server/fake_ntlm --# set source directory so fake_ntlm can find the test files --CURL_NTLM_AUTH_SRCDIR=%SRCDIR --# set source directory so fake_ntlm can find the test and log files --CURL_NTLM_LOGDIR=%LOGDIR --# set the test number --CURL_NTLM_AUTH_TESTNUM=%TESTNUMBER -- -- --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -u testuser:anypasswd --ntlm-wb -+ -+http://%HOSTIP:%HTTPPORT/junk -J -O --show-headers --output-dir %LOGDIR - -- --chkhostname curlhost -- - - -+# - # Verify data after the test has been "shot" - - --GET /%TESTNUMBER HTTP/1.1 --Host: %HOSTIP:%HTTPPORT --Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA --User-Agent: curl/%VERSION --Accept: */* -- --GET /%TESTNUMBER HTTP/1.1 -+GET /junk HTTP/1.1 - Host: %HOSTIP:%HTTPPORT --Authorization: NTLM TlRMTVNTUAADAAAAGAAYAE8AAAAYABgAZwAAAAAAAABAAAAACAAIAEAAAAAHAAcASAAAAAAAAAAAAAAAggEAAHRlc3R1c2VyVU5LTk9XTlpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOQ== - User-Agent: curl/%VERSION - Accept: */* - - -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 6 -+Connection: close -+Content-Disposition: inline; filename="name%TESTNUMBER" -+Content-Type: text/html -+ -+12345 -+ -+ - --# Input and output (type 1 message) for fake_ntlm -- -- --YR -- -- --YR TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA -- -- --# Input and output (type 3 message) for fake_ntlm -- -- --TT TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== -- -- --KK TlRMTVNTUAADAAAAGAAYAE8AAAAYABgAZwAAAAAAAABAAAAACAAIAEAAAAAHAAcASAAAAAAAAAAAAAAAggEAAHRlc3R1c2VyVU5LTk9XTlpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOQ== -- -- - -diff --git a/tests/data/test1311 b/tests/data/test1311 -index 8e48794a0..1a14547ce 100644 ---- a/tests/data/test1311 -+++ b/tests/data/test1311 -@@ -25,22 +25,14 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -J output in -- --debug -- - - http - - - HTTP GET with -J and Content-Disposition - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O --output-dir %LOGDIR - - - -diff --git a/tests/data/test1312 b/tests/data/test1312 -index c8170a8af..b67fdded7 100644 ---- a/tests/data/test1312 -+++ b/tests/data/test1312 -@@ -25,22 +25,14 @@ Content-Disposition: inline; filename="name%TESTNUMBER;weird" - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -J output in -- --debug -- - - http - - - HTTP GET with -J, Content-Disposition and ; in filename - -- --CURL_TESTDIR=%LOGDIR -- - --%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -+%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O --output-dir %LOGDIR - - - -diff --git a/tests/data/test1313 b/tests/data/test1313 -index 8a2859744..922dbc761 100644 ---- a/tests/data/test1313 -+++ b/tests/data/test1313 -@@ -25,22 +25,14 @@ Content-Disposition: inline; filename='name%TESTNUMBER - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -J output in -- --debug -- - - http - - - HTTP GET with -J, Content-Disposition, uneven quotes - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O --output-dir %LOGDIR - - - -diff --git a/tests/data/test1316 b/tests/data/test1316 -index b6b8a1896..c3f70878a 100644 ---- a/tests/data/test1316 -+++ b/tests/data/test1316 -@@ -19,15 +19,7 @@ Magic: sure you can FTP me - - - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- --HTTP/1.1 200 Mighty fine indeed --Magic: sure you can FTP me -- --HTTP/1.1 200 Mighty fine indeed --Magic: sure you can FTP me -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -39,7 +31,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -68,6 +60,9 @@ ftp://ftp.%TESTNUMBER:%FTPPORT/ -p -x %HOSTIP:%PROXYPORT - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test132 b/tests/data/test132 -index 8aa2f7906..47748494b 100644 ---- a/tests/data/test132 -+++ b/tests/data/test132 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -49,6 +47,9 @@ machine %HOSTIP login user2 password passwd2 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER mary - PASS mark -diff --git a/tests/data/test133 b/tests/data/test133 -index c8d2f9039..f80d840ab 100644 ---- a/tests/data/test133 -+++ b/tests/data/test133 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -49,6 +47,9 @@ machine %HOSTIP login mary password drfrank - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER mary - PASS drfrank -diff --git a/tests/data/test1334 b/tests/data/test1334 -index 88a41d8b2..1a13864c2 100644 ---- a/tests/data/test1334 -+++ b/tests/data/test1334 -@@ -23,22 +23,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O without Content-Disposition, -D file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - -diff --git a/tests/data/test1335 b/tests/data/test1335 -index 4d64ea877..a0b3aae65 100644 ---- a/tests/data/test1335 -+++ b/tests/data/test1335 -@@ -23,22 +23,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O without Content-Disposition, -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir %LOGDIR - - - -diff --git a/tests/data/test1336 b/tests/data/test1336 -index 993d8c6f8..dd93b5f9f 100644 ---- a/tests/data/test1336 -+++ b/tests/data/test1336 -@@ -24,26 +24,15 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O and Content-Disposition, -D file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # -@@ -74,6 +63,8 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -- -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1337 b/tests/data/test1337 -index 4b954d063..5dbddeea6 100644 ---- a/tests/data/test1337 -+++ b/tests/data/test1337 -@@ -24,26 +24,15 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O and Content-Disposition, -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O -D - --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # -@@ -71,6 +60,8 @@ Content-Type: text/html - Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - -- -+> -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1338 b/tests/data/test1338 -index c1c271a95..bc7b641e6 100644 ---- a/tests/data/test1338 -+++ b/tests/data/test1338 -@@ -24,22 +24,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O and -J output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -J without Content-Disposition, -D file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D %LOGDIR/heads%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - -diff --git a/tests/data/test1339 b/tests/data/test1339 -index a46934d3a..a3533841d 100644 ---- a/tests/data/test1339 -+++ b/tests/data/test1339 -@@ -24,22 +24,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O and -J output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -J without Content-Disposition, -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D - -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D - --output-dir %LOGDIR - - - -diff --git a/tests/data/test134 b/tests/data/test134 -index d0716c3d1..aa104bf15 100644 ---- a/tests/data/test134 -+++ b/tests/data/test134 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -51,6 +49,9 @@ machine %HOSTIP login user2 password passwd2 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER romulus - PASS rhemus -diff --git a/tests/data/test1340 b/tests/data/test1340 -index ebec701a6..9b6c092da 100644 ---- a/tests/data/test1340 -+++ b/tests/data/test1340 -@@ -25,22 +25,14 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O and -J output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -J and Content-Disposition, -D file - -- --CURL_TESTDIR=%PWD/%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D %LOGDIR/heads%TESTNUMBER -w "curl saved to filename %{filename_effective}\n" -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D %LOGDIR/heads%TESTNUMBER -w "curl saved to filename %{filename_effective}\n" --output-dir %LOGDIR - - - -@@ -71,7 +63,7 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - --curl saved to filename %PWD/%LOGDIR/name%TESTNUMBER -+curl saved to filename %LOGDIR/name%TESTNUMBER - - - -diff --git a/tests/data/test1341 b/tests/data/test1341 -index 75d9daae7..74cfd3b35 100644 ---- a/tests/data/test1341 -+++ b/tests/data/test1341 -@@ -25,22 +25,14 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O and -J output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -J and Content-Disposition, -D stdout - -- --CURL_TESTDIR=%PWD/%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D - -w "curl saved to filename %{filename_effective}\n" -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O -D - -w "curl saved to filename %{filename_effective}\n" --output-dir %LOGDIR - - - -@@ -68,7 +60,7 @@ Connection: close - Content-Type: text/html - Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - --curl saved to filename %PWD/%LOGDIR/name%TESTNUMBER -+curl saved to filename %LOGDIR/name%TESTNUMBER - - - -diff --git a/tests/data/test1342 b/tests/data/test1342 -index 39dbfab57..6d039f7ee 100644 ---- a/tests/data/test1342 -+++ b/tests/data/test1342 -@@ -23,22 +23,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i without Content-Disposition, -D file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D %LOGDIR/heads%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - -diff --git a/tests/data/test1343 b/tests/data/test1343 -index 6a9eb7dc8..c6a18f2ba 100644 ---- a/tests/data/test1343 -+++ b/tests/data/test1343 -@@ -23,22 +23,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i without Content-Disposition, -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D - -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D - --output-dir %LOGDIR - - - -diff --git a/tests/data/test1344 b/tests/data/test1344 -index ba4b38976..de440520e 100644 ---- a/tests/data/test1344 -+++ b/tests/data/test1344 -@@ -24,26 +24,15 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i and Content-Disposition, -D file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D %LOGDIR/heads%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # -@@ -82,6 +71,8 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -- -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1345 b/tests/data/test1345 -index a9298e4e2..a093e5d8c 100644 ---- a/tests/data/test1345 -+++ b/tests/data/test1345 -@@ -24,26 +24,15 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i and Content-Disposition, -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D - -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -D - --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # -@@ -79,6 +68,8 @@ Content-Type: text/html - Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - -- -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1346 b/tests/data/test1346 -index bab67cb63..af2a35cba 100644 ---- a/tests/data/test1346 -+++ b/tests/data/test1346 -@@ -23,22 +23,14 @@ Content-Type: text/html - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i without Content-Disposition, without -D - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O --output-dir %LOGDIR - - - -diff --git a/tests/data/test1347 b/tests/data/test1347 -index 868e2611c..bbef9f409 100644 ---- a/tests/data/test1347 -+++ b/tests/data/test1347 -@@ -24,26 +24,15 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - http - - - HTTP GET with -O -i and Content-Disposition, without -D - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -O --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # -@@ -71,6 +60,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - - -diff --git a/tests/data/test1348 b/tests/data/test1348 -index 3de0b4a93..fde0ffb24 100644 ---- a/tests/data/test1348 -+++ b/tests/data/test1348 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without Content-Disposition inside, using -O - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1349 b/tests/data/test1349 -index d2565496c..416736667 100644 ---- a/tests/data/test1349 -+++ b/tests/data/test1349 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test135 b/tests/data/test135 -index 3dc1d531f..cdb548362 100644 ---- a/tests/data/test135 -+++ b/tests/data/test135 -@@ -38,6 +38,9 @@ FTP retrieve a byte-range - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1350 b/tests/data/test1350 -index b5568f536..f896f22b1 100644 ---- a/tests/data/test1350 -+++ b/tests/data/test1350 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D - --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1351 b/tests/data/test1351 -index 93232d55c..947300f67 100644 ---- a/tests/data/test1351 -+++ b/tests/data/test1351 -@@ -17,27 +17,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -J -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1352 b/tests/data/test1352 -index 0649289b6..a74d2f33f 100644 ---- a/tests/data/test1352 -+++ b/tests/data/test1352 -@@ -17,27 +17,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -J -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D - --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1353 b/tests/data/test1353 -index 8e0ad50e4..a4df5d8ba 100644 ---- a/tests/data/test1353 -+++ b/tests/data/test1353 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -i -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1354 b/tests/data/test1354 -index 506ec90e4..3413d4677 100644 ---- a/tests/data/test1354 -+++ b/tests/data/test1354 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -i -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D - --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1355 b/tests/data/test1355 -index fa19fabc4..e99dd015d 100644 ---- a/tests/data/test1355 -+++ b/tests/data/test1355 -@@ -16,27 +16,22 @@ mooo - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file without C-D inside, using -O -i, without -D - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i --output-dir %LOGDIR - - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1356 b/tests/data/test1356 -index 0c326f48c..77a88be56 100644 ---- a/tests/data/test1356 -+++ b/tests/data/test1356 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with Content-Disposition inside, using -O - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -74,6 +66,8 @@ MOOOO - - - -- -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1357 b/tests/data/test1357 -index 9d395a875..b0943b7f6 100644 ---- a/tests/data/test1357 -+++ b/tests/data/test1357 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -94,6 +86,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -- -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1358 b/tests/data/test1358 -index 973ef7cf4..c71520c95 100644 ---- a/tests/data/test1358 -+++ b/tests/data/test1358 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -D - --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -92,5 +84,8 @@ MOOOO - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1359 b/tests/data/test1359 -index fc1eb3728..63cdc4ce3 100644 ---- a/tests/data/test1359 -+++ b/tests/data/test1359 -@@ -25,30 +25,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -J -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -96,5 +88,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test136 b/tests/data/test136 -index ef0b2c49a..f71f4b36a 100644 ---- a/tests/data/test136 -+++ b/tests/data/test136 -@@ -28,6 +28,9 @@ FTP with user and no password - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER user - PASS -diff --git a/tests/data/test1360 b/tests/data/test1360 -index 1fb80eecd..6f8732a1e 100644 ---- a/tests/data/test1360 -+++ b/tests/data/test1360 -@@ -25,30 +25,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -J -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -J -D - --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -93,5 +85,8 @@ MOOOO - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1361 b/tests/data/test1361 -index 6b9af1ad8..c80b097a5 100644 ---- a/tests/data/test1361 -+++ b/tests/data/test1361 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -i -D file - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D %LOGDIR/heads%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D %LOGDIR/heads%TESTNUMBER --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -95,5 +87,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1362 b/tests/data/test1362 -index 03d99047b..9e4890ae0 100644 ---- a/tests/data/test1362 -+++ b/tests/data/test1362 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -i -D stdout - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D - -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -D - --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -92,5 +84,8 @@ MOOOO - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1363 b/tests/data/test1363 -index 009f68cae..4ef72cf77 100644 ---- a/tests/data/test1363 -+++ b/tests/data/test1363 -@@ -24,30 +24,22 @@ MOOOO - - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O output in, using the CURL_TESTDIR variable -- --debug -- - - ftp - - - FTP download, file with C-D inside, using -O -i, without -D - -- --CURL_TESTDIR=%LOGDIR -- - --ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i -+ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -O -i --output-dir %LOGDIR - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -75,5 +67,8 @@ MOOOO - - - -+ -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1364 b/tests/data/test1364 -index 0ea1e2b12..2b3b566f6 100644 ---- a/tests/data/test1364 -+++ b/tests/data/test1364 -@@ -32,9 +32,6 @@ HTTP GET -o fname without Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -65,5 +62,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1365 b/tests/data/test1365 -index abd371c01..1a28a77ed 100644 ---- a/tests/data/test1365 -+++ b/tests/data/test1365 -@@ -32,9 +32,6 @@ HTTP GET -o fname without Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -62,5 +59,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1366 b/tests/data/test1366 -index 78f5573ea..1107c2281 100644 ---- a/tests/data/test1366 -+++ b/tests/data/test1366 -@@ -33,9 +33,6 @@ HTTP GET -o fname and Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -67,5 +64,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1367 b/tests/data/test1367 -index 24929365a..5d1efa3a9 100644 ---- a/tests/data/test1367 -+++ b/tests/data/test1367 -@@ -33,9 +33,6 @@ HTTP GET -o fname and Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -64,5 +61,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1368 b/tests/data/test1368 -index 1d6d181b0..c9ee02169 100644 ---- a/tests/data/test1368 -+++ b/tests/data/test1368 -@@ -33,9 +33,6 @@ HTTP GET -o fname -J without Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -66,5 +63,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1369 b/tests/data/test1369 -index 48fd31806..93627e6a4 100644 ---- a/tests/data/test1369 -+++ b/tests/data/test1369 -@@ -33,9 +33,6 @@ HTTP GET -o fname -J without Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -63,5 +60,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test137 b/tests/data/test137 -index 33b93589e..8154af88d 100644 ---- a/tests/data/test137 -+++ b/tests/data/test137 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/lululul/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1370 b/tests/data/test1370 -index d76940143..637444c54 100644 ---- a/tests/data/test1370 -+++ b/tests/data/test1370 -@@ -34,9 +34,6 @@ HTTP GET -o fname -J and Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -68,5 +65,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1371 b/tests/data/test1371 -index 8565363b9..d05c1a15b 100644 ---- a/tests/data/test1371 -+++ b/tests/data/test1371 -@@ -34,9 +34,6 @@ HTTP GET -o fname -J and Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -65,5 +62,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1372 b/tests/data/test1372 -index 76b367132..a39a243c9 100644 ---- a/tests/data/test1372 -+++ b/tests/data/test1372 -@@ -32,9 +32,6 @@ HTTP GET -o fname -i without Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -72,5 +69,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1373 b/tests/data/test1373 -index c475deb9f..7d94775d6 100644 ---- a/tests/data/test1373 -+++ b/tests/data/test1373 -@@ -32,9 +32,6 @@ HTTP GET -o fname -i without Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -69,5 +66,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1374 b/tests/data/test1374 -index aa2b3e346..95af862fa 100644 ---- a/tests/data/test1374 -+++ b/tests/data/test1374 -@@ -33,9 +33,6 @@ HTTP GET -o fname -i and Content-Disposition, -D file - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -75,5 +72,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1375 b/tests/data/test1375 -index 6df552636..f56a7d90b 100644 ---- a/tests/data/test1375 -+++ b/tests/data/test1375 -@@ -33,9 +33,6 @@ HTTP GET -o fname -i and Content-Disposition, -D stdout - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -72,5 +69,9 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1376 b/tests/data/test1376 -index f3d36e0af..5b3280b03 100644 ---- a/tests/data/test1376 -+++ b/tests/data/test1376 -@@ -32,9 +32,6 @@ HTTP GET -o fname -i without Content-Disposition, without -D - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -62,5 +59,8 @@ Content-Type: text/html - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1377 b/tests/data/test1377 -index d1a6b7213..4bdc864bc 100644 ---- a/tests/data/test1377 -+++ b/tests/data/test1377 -@@ -33,9 +33,6 @@ HTTP GET -o fname -i and Content-Disposition, without -D - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -i -o %LOGDIR/outfile%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # -@@ -63,6 +60,10 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange - - - -+ -+%LOGDIR/%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - - -diff --git a/tests/data/test1378 b/tests/data/test1378 -index 7348a3f17..f8551251a 100644 ---- a/tests/data/test1378 -+++ b/tests/data/test1378 -@@ -25,13 +25,13 @@ FTP DL, file without Content-Disposition inside, using -o fname - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -51,6 +51,9 @@ mooo - - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - - -diff --git a/tests/data/test1379 b/tests/data/test1379 -index 0b8d20ae0..9cecb0eae 100644 ---- a/tests/data/test1379 -+++ b/tests/data/test1379 -@@ -25,13 +25,13 @@ FTP DL, file without C-D inside, using -o fname -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -72,5 +72,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test138 b/tests/data/test138 -index db3b6ec7d..e00c3110c 100644 ---- a/tests/data/test138 -+++ b/tests/data/test138 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/lululul/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1380 b/tests/data/test1380 -index 187dd8cdb..d53422395 100644 ---- a/tests/data/test1380 -+++ b/tests/data/test1380 -@@ -25,13 +25,13 @@ FTP DL, file without C-D inside, using -o fname -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -69,5 +69,8 @@ mooo - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1381 b/tests/data/test1381 -index 4ba20eb3e..28c2af5fe 100644 ---- a/tests/data/test1381 -+++ b/tests/data/test1381 -@@ -26,13 +26,13 @@ FTP DL, file without C-D inside, using -o fname -J -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -J -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -73,5 +73,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1382 b/tests/data/test1382 -index 26ff7acbe..d96ad468a 100644 ---- a/tests/data/test1382 -+++ b/tests/data/test1382 -@@ -26,13 +26,13 @@ FTP DL, file without C-D inside, using -o fname -J -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -J -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -70,5 +70,8 @@ mooo - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1383 b/tests/data/test1383 -index d4c5c8285..2c9f33291 100644 ---- a/tests/data/test1383 -+++ b/tests/data/test1383 -@@ -25,13 +25,13 @@ FTP DL, file without C-D inside, using -o fname -i -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -72,5 +72,8 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1384 b/tests/data/test1384 -index af7afdf76..1dd2aa280 100644 ---- a/tests/data/test1384 -+++ b/tests/data/test1384 -@@ -25,13 +25,13 @@ FTP DL, file without C-D inside, using -o fname -i -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -69,5 +69,8 @@ mooo - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1385 b/tests/data/test1385 -index d2038ee92..8654da654 100644 ---- a/tests/data/test1385 -+++ b/tests/data/test1385 -@@ -25,13 +25,13 @@ FTP DL, file without C-D inside, using -o fname -i, without -D - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -52,5 +52,8 @@ mooo - - - -+ -+%LOGDIR/file%TESTNUMBER -+ - - -diff --git a/tests/data/test1386 b/tests/data/test1386 -index 0aaf66419..44b8dcd42 100644 ---- a/tests/data/test1386 -+++ b/tests/data/test1386 -@@ -33,13 +33,13 @@ FTP DL, file with Content-Disposition inside, using -o fname - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -67,5 +67,9 @@ MOOOO - - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1387 b/tests/data/test1387 -index 0f124d870..6a24b7678 100644 ---- a/tests/data/test1387 -+++ b/tests/data/test1387 -@@ -33,13 +33,13 @@ FTP DL, file with C-D inside, using -o fname -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -87,5 +87,9 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1388 b/tests/data/test1388 -index d78844e77..a26a829c0 100644 ---- a/tests/data/test1388 -+++ b/tests/data/test1388 -@@ -33,13 +33,13 @@ FTP DL, file with C-D inside, using -o fname -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -83,6 +83,10 @@ MOOOO - - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - - -diff --git a/tests/data/test1389 b/tests/data/test1389 -index 0863a4013..77f7b5f27 100644 ---- a/tests/data/test1389 -+++ b/tests/data/test1389 -@@ -34,13 +34,13 @@ FTP DL, file with C-D inside, using -o fname -J -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -J -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -87,6 +87,10 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - - -diff --git a/tests/data/test139 b/tests/data/test139 -index 160f628e2..61a0da601 100644 ---- a/tests/data/test139 -+++ b/tests/data/test139 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/%TESTNUMBER -z "1 jan 1989" - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1390 b/tests/data/test1390 -index a856d1e8d..be7cf2ed9 100644 ---- a/tests/data/test1390 -+++ b/tests/data/test1390 -@@ -34,13 +34,13 @@ FTP DL, file with C-D inside, using -o fname -J -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -J -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -85,5 +85,9 @@ MOOOO - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1391 b/tests/data/test1391 -index ae1495eec..c0c5bc58a 100644 ---- a/tests/data/test1391 -+++ b/tests/data/test1391 -@@ -33,13 +33,13 @@ FTP DL, file with C-D inside, using -o fname -i -D file - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i -D %LOGDIR/heads%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -87,5 +87,9 @@ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1392 b/tests/data/test1392 -index f715fe8b3..49472104e 100644 ---- a/tests/data/test1392 -+++ b/tests/data/test1392 -@@ -33,13 +33,13 @@ FTP DL, file with C-D inside, using -o fname -i -D stdout - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i -D - - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -84,5 +84,9 @@ MOOOO - s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test1393 b/tests/data/test1393 -index dc7a6f934..81734206e 100644 ---- a/tests/data/test1393 -+++ b/tests/data/test1393 -@@ -33,13 +33,13 @@ FTP DL, file with C-D inside, using -o fname -i, without -D - - ftp://%HOSTIP:%FTPPORT/path/file%TESTNUMBER -o %LOGDIR/download%TESTNUMBER -i - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/file%TESTNUMBER %LOGDIR/name%TESTNUMBER -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -67,5 +67,9 @@ MOOOO - - - -+ -+%LOGDIR/file%TESTNUMBER -+%LOGDIR/name%TESTNUMBER -+ - - -diff --git a/tests/data/test140 b/tests/data/test140 -index 5e29f5c7c..cacef2ae2 100644 ---- a/tests/data/test140 -+++ b/tests/data/test140 -@@ -30,6 +30,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/%TESTNUMBER -z "1 jan 2004" - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1405 b/tests/data/test1405 -index 8a13a688a..5ca006a13 100644 ---- a/tests/data/test1405 -+++ b/tests/data/test1405 -@@ -42,6 +42,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -Q "NOOP 1" -Q "+NOOP 2" -Q "-NOOP 3" -Q "*FA - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1408 b/tests/data/test1408 -index 925be875b..5c7f6493d 100644 ---- a/tests/data/test1408 -+++ b/tests/data/test1408 -@@ -40,7 +40,7 @@ Set-Cookie: time=2 - - - cookies --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test141 b/tests/data/test141 -index 425a98f2a..5ffbc4523 100644 ---- a/tests/data/test141 -+++ b/tests/data/test141 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/blalbla/%TESTNUMBER -I - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1411 b/tests/data/test1411 -index bd8a8dd68..9c75a225c 100644 ---- a/tests/data/test1411 -+++ b/tests/data/test1411 -@@ -2,7 +2,7 @@ - - - HTTP --PUT -+HTTP PUT - - - -diff --git a/tests/data/test1414 b/tests/data/test1414 -index 4be9b5422..9fc2a56ff 100644 ---- a/tests/data/test1414 -+++ b/tests/data/test1414 -@@ -38,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -P - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^(EPRT \|1\|)(.*)/$1/ - s/^(PORT)(.*)/$1/ -diff --git a/tests/data/test142 b/tests/data/test142 -index c4ad11a6d..db17e3074 100644 ---- a/tests/data/test142 -+++ b/tests/data/test142 -@@ -26,6 +26,9 @@ ftp://%HOSTIP:%FTPPORT/part1/part2/part3/part4/part5/part6/part7/part8/part9/par - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1422 b/tests/data/test1422 -index c62c2cbda..9aa95bf27 100644 ---- a/tests/data/test1422 -+++ b/tests/data/test1422 -@@ -24,10 +24,7 @@ Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=str//nge - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -O and -J output in, using the CURL_TESTDIR variable - --debug - file - - -@@ -36,11 +33,8 @@ http - - HTTP GET with -O -J and Content-Disposition (empty file) - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O file://%PWD/%LOGDIR/name%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O file://%FILE_PWD/%LOGDIR/name%TESTNUMBER --output-dir %LOGDIR - - - -diff --git a/tests/data/test1423 b/tests/data/test1423 -index f269cc0b0..16a4cf31f 100644 ---- a/tests/data/test1423 -+++ b/tests/data/test1423 -@@ -30,11 +30,8 @@ file - HTTP GET -o fname without Content-Disposition (empty file) - - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER file://%PWD/%LOGDIR/outfile%TESTNUMBER -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/outfile%TESTNUMBER file://%FILE_PWD/%LOGDIR/outfile%TESTNUMBER - -- --perl %SRCDIR/libtest/notexists.pl %LOGDIR/%TESTNUMBER -- - - - # -@@ -51,5 +48,8 @@ Accept: */* - - - -+ -+%LOGDIR/%TESTNUMBER -+ - - -diff --git a/tests/data/test1425 b/tests/data/test1425 -index f51483dd0..4e13dbef8 100644 -Binary files a/tests/data/test1425 and b/tests/data/test1425 differ -diff --git a/tests/data/test1426 b/tests/data/test1426 -index d53138afa..792cc4bab 100644 -Binary files a/tests/data/test1426 and b/tests/data/test1426 differ -diff --git a/tests/data/test143 b/tests/data/test143 -index ed89e70de..8984a3f1f 100644 ---- a/tests/data/test143 -+++ b/tests/data/test143 -@@ -28,6 +28,9 @@ FTP URL with type=a - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1435 b/tests/data/test1435 -index 0e1e34f55..321ea4c02 100644 ---- a/tests/data/test1435 -+++ b/tests/data/test1435 -@@ -3,7 +3,7 @@ - - HTTP - HTTP GET --unix sockets -+UnixSockets - - - -@@ -19,7 +19,7 @@ Based on test300 - - - --unix-sockets -+UnixSockets - - - http-unix -diff --git a/tests/data/test1436 b/tests/data/test1436 -index 352ef34e0..f82384e58 100644 ---- a/tests/data/test1436 -+++ b/tests/data/test1436 -@@ -3,7 +3,7 @@ - - HTTP - HTTP GET --unix sockets -+UnixSockets - - - -@@ -33,7 +33,7 @@ Third - - - --unix-sockets -+UnixSockets - - - http-unix -diff --git a/tests/data/test1438 b/tests/data/test1438 -index 90610a829..cbf19550d 100644 ---- a/tests/data/test1438 -+++ b/tests/data/test1438 -@@ -44,7 +44,7 @@ Connection: close - Content-Type: text/plain - - testdata --HTTP -+http - - - GET /%TESTNUMBER HTTP/1.1 -diff --git a/tests/data/test144 b/tests/data/test144 -index be2ca5c8c..e7a983bca 100644 ---- a/tests/data/test144 -+++ b/tests/data/test144 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/ -P - -l - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1440 b/tests/data/test1440 -index dbdfc7361..8ae45753d 100644 ---- a/tests/data/test1440 -+++ b/tests/data/test1440 -@@ -19,7 +19,7 @@ file - Check --write-out with trailing %{ - - --file://localhost/%PWD/%LOGDIR/non-existent-file.txt --write-out '%{' -+file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out '%{' - - - -diff --git a/tests/data/test1441 b/tests/data/test1441 -index 2ff6be036..16b2a8716 100644 ---- a/tests/data/test1441 -+++ b/tests/data/test1441 -@@ -19,7 +19,7 @@ file - Check --write-out with trailing % - - --file://localhost/%PWD/%LOGDIR/non-existent-file.txt --write-out '%' -+file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out '%' - - - -diff --git a/tests/data/test1442 b/tests/data/test1442 -index 02ecea67f..0825a1e02 100644 ---- a/tests/data/test1442 -+++ b/tests/data/test1442 -@@ -19,7 +19,7 @@ file - Check --write-out with trailing \ - - --file://localhost/%PWD/%LOGDIR/non-existent-file.txt --write-out '\' -+file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt --write-out '\' - - - -diff --git a/tests/data/test1443 b/tests/data/test1443 -index bbfaf7f1b..45aead932 100644 ---- a/tests/data/test1443 -+++ b/tests/data/test1443 -@@ -25,28 +25,17 @@ Connection: close - # - # Client-side - --# This relies on the debug feature to allow us to set a directory --# in which to store the -O output -- --debug -- - - http - - - HTTP GET with -O and --remote-time - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O --remote-time -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -O --remote-time --output-dir %LOGDIR - - # Verify the mtime of the file. The mtime is specifically chosen to be an even - # number so that it can be represented exactly on a FAT filesystem. -- --perl -e 'exit((stat("%LOGDIR/%TESTNUMBER"))[9] != 960898200)' -- - - - # -@@ -62,5 +51,8 @@ Accept: */* - - 12345 - -+ -+%PERL -e 'exit((stat("%LOGDIR/%TESTNUMBER"))[9] != 960898200)' -+ - - -diff --git a/tests/data/test1444 b/tests/data/test1444 -index 61b3a29f4..ad1dc4634 100644 ---- a/tests/data/test1444 -+++ b/tests/data/test1444 -@@ -28,15 +28,13 @@ FTP with --remote-time - - ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --remote-time - --# Verify the mtime of the file. The mtime is specifically chosen to be an even --# number so that it can be represented exactly on a FAT filesystem. -- --perl -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 1234567890)' -- - - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -48,5 +46,10 @@ SIZE %TESTNUMBER - RETR %TESTNUMBER - QUIT - -+# Verify the mtime of the file. The mtime is specifically chosen to be an even -+# number so that it can be represented exactly on a FAT filesystem. -+ -+%PERL -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 1234567890)' -+ - - -diff --git a/tests/data/test1445 b/tests/data/test1445 -index fee8932f1..f52be8f72 100644 ---- a/tests/data/test1445 -+++ b/tests/data/test1445 -@@ -15,7 +15,7 @@ FILE - file - - --perl %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir - - - file:// with --remote-time -@@ -23,13 +23,13 @@ file:// with --remote-time - - file://localhost%FILE_PWD/%LOGDIR/test%TESTNUMBER.dir/plainfile.txt --remote-time - -- --perl %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir && \ --perl -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 946728000)' -- - - - # Verify data after the test has been "shot" - -+ -+%PERL %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir && \ -+%PERL -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 946728000)' -+ - - -diff --git a/tests/data/test1446 b/tests/data/test1446 -index f633ac17a..bec6dd7f3 100644 ---- a/tests/data/test1446 -+++ b/tests/data/test1446 -@@ -18,7 +18,7 @@ SFTP - sftp - - --perl %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP with --remote-time -@@ -26,17 +26,14 @@ SFTP with --remote-time - - --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/rofile.txt --insecure --remote-time - -- --perl %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir && \ --perl -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 978264000)' -- - - - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir && \ -+%PERL -e 'exit((stat("%LOGDIR/curl%TESTNUMBER.out"))[9] != 978264000)' -+ - - -diff --git a/tests/data/test1448 b/tests/data/test1448 -index 6a9ba5212..33aedc4f0 100644 ---- a/tests/data/test1448 -+++ b/tests/data/test1448 -@@ -39,15 +39,13 @@ OK - http - - --idn -+IDN -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - Redirect following to UTF-8 IDN host name - -diff --git a/tests/data/test1449 b/tests/data/test1449 -index 0b9de0192..d761f3c0e 100644 ---- a/tests/data/test1449 -+++ b/tests/data/test1449 -@@ -27,6 +27,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -r 36893488147419103232- - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test145 b/tests/data/test145 -index 53f3f631d..7f12b36f3 100644 ---- a/tests/data/test145 -+++ b/tests/data/test145 -@@ -30,6 +30,9 @@ ftp://%HOSTIP:%FTPPORT/ -P - -l - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 19 - -diff --git a/tests/data/test1451 b/tests/data/test1451 -index 9fdd68a61..be4240118 100644 ---- a/tests/data/test1451 -+++ b/tests/data/test1451 -@@ -28,9 +28,6 @@ Basic SMB request - - -u 'curltest:curltest' smb://%HOSTIP:%SMBPORT/TESTS/%TESTNUMBER - -- --python3 -c "__import__('pkgutil').find_loader('impacket') or (__import__('sys').stdout.write('Test only works if Python package impacket is installed\n'), __import__('sys').exit(1))" -- - - - # -diff --git a/tests/data/test1454 b/tests/data/test1454 -index 4908a178d..dff914b11 100644 ---- a/tests/data/test1454 -+++ b/tests/data/test1454 -@@ -14,7 +14,7 @@ - # Client-side - - --!ipv6 -+!IPv6 - - - http -diff --git a/tests/data/test1456 b/tests/data/test1456 -index 3f3a74783..d846b41eb 100644 ---- a/tests/data/test1456 -+++ b/tests/data/test1456 -@@ -31,7 +31,7 @@ These data aren't actually sent to the client - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test1459 b/tests/data/test1459 -index c05da3cb5..335b26576 100644 ---- a/tests/data/test1459 -+++ b/tests/data/test1459 -@@ -40,9 +40,5 @@ CURL_HOME=%PWD/%LOGDIR/test%TESTNUMBER.dir - - 60 - -- --disable -- - - -- -diff --git a/tests/data/test146 b/tests/data/test146 -index 803fbfc4d..c7586573e 100644 ---- a/tests/data/test146 -+++ b/tests/data/test146 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/first/dir/here/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/%TESTNU - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1460 b/tests/data/test1460 -index c3180ff92..7422d4b99 100644 ---- a/tests/data/test1460 -+++ b/tests/data/test1460 -@@ -11,33 +11,26 @@ HTTP GET - - - HTTP/1.1 200 swsclose -- 12345 --fooo --54 3 2 1 -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake - Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange -+Content-Length: 4 - -+hej - - - - # - # Client-side - --# this relies on the debug feature to allow us to set directory to store the --# -J output in -- --debug -- - - http - - - HTTP GET with -Ji and Content-Disposition with existing file - -- --CURL_TESTDIR=%LOGDIR -- - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -Ji -O -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -Ji -O --output-dir %LOGDIR - - - initial content -@@ -47,9 +40,9 @@ initial content - # - # Verify data after the test has been "shot" - --# Warning: --include and --remote-header-name cannot be combined. -+# Warning: Failed to open the file log/name1460: File exists - --2 -+23 - - - initial content -diff --git a/tests/data/test1461 b/tests/data/test1461 -index 424af943f..f1c481ec6 100644 ---- a/tests/data/test1461 -+++ b/tests/data/test1461 -@@ -13,6 +13,9 @@ - # - # Client-side - -+ -+manual -+ - - none - -@@ -34,10 +37,10 @@ curl important --help - Usage: curl [options...] - -d, --data HTTP POST data - -f, --fail Fail fast with no output on HTTP errors -- -h, --help Get help for commands -- -i, --include Include response headers in output -+ -h, --help Get help for commands - -o, --output Write to file instead of stdout - -O, --remote-name Write output to file named as remote file -+ -i, --show-headers Show response headers in output - -s, --silent Silent mode - -T, --upload-file Transfer local FILE to destination - -u, --user Server user and password -@@ -45,9 +48,13 @@ Usage: curl [options...] - -v, --verbose Make the operation more talkative - -V, --version Show version number and quit - --This is not the full help, this menu is stripped into categories. --Use "--help category" to get an overview of all categories. --For all options use the manual or "--help all". -+This is not the full help; this menu is split into categories. -+Use "--help category" to get an overview of all categories, which are: -+auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, -+output, pop3, post, proxy, scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, -+upload, verbose. -+Use "--help all" to list all options -+Use "--help [option]" to view documentation for a given option - - - -diff --git a/tests/data/test1462 b/tests/data/test1462 -index 654e44344..a3cc46e31 100644 ---- a/tests/data/test1462 -+++ b/tests/data/test1462 -@@ -31,31 +31,33 @@ curl invalid category --help - 0 - - --Usage: curl [options...] --Invalid category provided, here is a list of all categories: -+Unknown category provided, here is a list of all categories: - -- auth Different types of authentication methods -- connection Low level networking operations -+ auth Authentication methods -+ connection Manage connections - curl The command line tool itself -- dns General DNS options -- file FILE protocol options -- ftp FTP protocol options -- http HTTP and HTTPS protocol options -- imap IMAP protocol options -- misc Options that don't fit into any other category -+ deprecated Legacy -+ dns Names and resolving -+ file FILE protocol -+ ftp FTP protocol -+ global Global options -+ http HTTP and HTTPS protocol -+ imap IMAP protocol -+ ldap LDAP protocol - output Filesystem output -- pop3 POP3 protocol options -- post HTTP Post specific options -- proxy All options related to proxies -- scp SCP protocol options -- sftp SFTP protocol options -- smtp SMTP protocol options -- ssh SSH protocol options -- telnet TELNET protocol options -- tftp TFTP protocol options -- tls All TLS/SSL related options -- upload All options for uploads -- verbose Options related to any kind of command line output of curl -+ pop3 POP3 protocol -+ post HTTP POST specific -+ proxy Options for proxies -+ scp SCP protocol -+ sftp SFTP protocol -+ smtp SMTP protocol -+ ssh SSH protocol -+ telnet TELNET protocol -+ tftp TFTP protocol -+ timeout Timeouts and delays -+ tls TLS/SSL related -+ upload Upload, sending data -+ verbose Tracing, logging etc - - - -diff --git a/tests/data/test1463 b/tests/data/test1463 -index 254b51b22..9fd527f78 100644 ---- a/tests/data/test1463 -+++ b/tests/data/test1463 -@@ -35,10 +35,10 @@ curl file category --help - 0 - - --Usage: curl [options...] --file: FILE protocol options -+file: FILE protocol - --create-file-mode File mode for created files - -I, --head Show document info only -+ -l, --list-only List only mode - -r, --range Retrieve only the bytes within RANGE - - -diff --git a/tests/data/test1464 b/tests/data/test1464 -index 6a0af34c2..59f58dfc5 100644 ---- a/tests/data/test1464 -+++ b/tests/data/test1464 -@@ -35,10 +35,10 @@ curl file category --help with lower/upper mix - 0 - - --Usage: curl [options...] --file: FILE protocol options -+file: FILE protocol - --create-file-mode File mode for created files - -I, --head Show document info only -+ -l, --list-only List only mode - -r, --range Retrieve only the bytes within RANGE - - -diff --git a/tests/data/test1467 b/tests/data/test1467 -index bf6ed8f38..568670a71 100644 ---- a/tests/data/test1467 -+++ b/tests/data/test1467 -@@ -4,7 +4,7 @@ - HTTP - HTTP GET - SOCKS5 --unix sockets -+UnixSockets - - - -@@ -32,14 +32,14 @@ Funny-head: yesyes - - - proxy --unix-sockets -+UnixSockets - - - http - socks5unix - - --HTTP GET via SOCKS5 proxy via unix sockets -+HTTP GET via SOCKS5 proxy via Unix sockets - - - --socks5 localhost%SOCKSUNIXPATH http://%HOSTIP:%HTTPPORT/%TESTNUMBER -diff --git a/tests/data/test1468 b/tests/data/test1468 -index dad25df12..9836434d4 100644 ---- a/tests/data/test1468 -+++ b/tests/data/test1468 -@@ -5,7 +5,7 @@ HTTP - HTTP GET - SOCKS5 - SOCKS5h --unix sockets -+UnixSockets - - - -@@ -33,14 +33,14 @@ Funny-head: yesyes - - - proxy --unix-sockets -+UnixSockets - - - http - socks5unix - - --HTTP GET with host name using SOCKS5h via unix sockets -+HTTP GET with host name using SOCKS5h via Unix sockets - - - http://this.is.a.host.name:%HTTPPORT/%TESTNUMBER --proxy socks5h://localhost%SOCKSUNIXPATH -diff --git a/tests/data/test147 b/tests/data/test147 -index 769043d48..b2772f607 100644 ---- a/tests/data/test147 -+++ b/tests/data/test147 -@@ -31,6 +31,9 @@ ftp://%HOSTIP:%FTPPORT/first/dir/here/%TESTNUMBER --ftp-create-dirs - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1470 b/tests/data/test1470 -index ad4fb711a..1c9389a4c 100644 ---- a/tests/data/test1470 -+++ b/tests/data/test1470 -@@ -6,7 +6,7 @@ HTTP - HTTP GET - SOCKS5 - SOCKS5h --unix sockets -+UnixSockets - - - -@@ -34,14 +34,14 @@ Funny-head: yesyes - - - proxy --unix-sockets -+UnixSockets - - - https - socks5unix - - --HTTPS GET with host name using SOCKS5h via unix sockets -+HTTPS GET with host name using SOCKS5h via Unix sockets - - - https://this.is.a.host.name:%HTTPSPORT/%TESTNUMBER -k --proxy socks5h://localhost%SOCKSUNIXPATH -diff --git a/tests/data/test1478 b/tests/data/test1478 -index c05766740..ef7b40372 100644 ---- a/tests/data/test1478 -+++ b/tests/data/test1478 -@@ -19,7 +19,7 @@ src/tool_listhelp.c is in sync with docs/cmdline-opts - - - --%SRCDIR/../scripts/managen listhelp %SRCDIR/../docs/cmdline-opts/*.md -+%SRCDIR/../scripts/managen -d %SRCDIR/../docs/cmdline-opts -I %SRCDIR/../include listhelp %SRCDIR/../docs/cmdline-opts/*.md - - - -diff --git a/tests/data/test148 b/tests/data/test148 -index 051d31a9d..c8ec7a6d1 100644 ---- a/tests/data/test148 -+++ b/tests/data/test148 -@@ -28,6 +28,9 @@ ftp://%HOSTIP:%FTPPORT/attempt/to/get/this/%TESTNUMBER --ftp-create-dirs - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1481 b/tests/data/test1481 -index ca638f513..5d79e6955 100644 ---- a/tests/data/test1481 -+++ b/tests/data/test1481 -@@ -26,7 +26,7 @@ http - - - proxy --ssl -+SSL - - - --libcurl with TLS version options -diff --git a/tests/data/test1482 b/tests/data/test1482 -new file mode 100644 -index 000000000..027ccf253 ---- /dev/null -+++ b/tests/data/test1482 -@@ -0,0 +1,87 @@ -+ -+ -+ -+HTTP -+HTTP GET -+chunked Transfer-Encoding -+DELAY -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked, chunked -+Connection: mooo -+ -+40 -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+30 -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -+21;heresatest=moooo -+cccccccccccccccccccccccccccccccc -+ -+0 -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked, chunked -+Connection: mooo -+ -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+writedelay: 10 -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP GET with double chunked in TE header -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked, chunked -+Connection: mooo -+ -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+ -+ -diff --git a/tests/data/test1483 b/tests/data/test1483 -new file mode 100644 -index 000000000..5bb59a9c9 ---- /dev/null -+++ b/tests/data/test1483 -@@ -0,0 +1,90 @@ -+ -+ -+ -+HTTP -+HTTP GET -+chunked Transfer-Encoding -+DELAY -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked -+Transfer-Encoding: chunked -+Connection: mooo -+ -+40 -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+30 -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -+21;heresatest=moooo -+cccccccccccccccccccccccccccccccc -+ -+0 -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked -+Transfer-Encoding: chunked -+Connection: mooo -+ -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+writedelay: 10 -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP GET with double chunked in TE header -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -D %LOGDIR/heads%TESTNUMBER -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Transfer-Encoding: chunked -+Transfer-Encoding: chunked -+Connection: mooo -+ -+%if !hyper -+chunky-trailer: header data -+another-header: yes -+%endif -+ -+ -+ -+ -diff --git a/tests/data/test1484 b/tests/data/test1484 -new file mode 100644 -index 000000000..52de029a0 ---- /dev/null -+++ b/tests/data/test1484 -@@ -0,0 +1,53 @@ -+ -+ -+ -+HTTP -+HTTP HEAD -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Transfer-Encoding: chunked -+ -+HEAD response with content -+ -+# make sure no data is written -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Transfer-Encoding: chunked -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP HEAD with response body to ignore -+ -+ -+-I http://%HOSTIP:%HTTPPORT/%TESTNUMBER --http1.1 -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+HEAD /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+ -diff --git a/tests/data/test1485 b/tests/data/test1485 -new file mode 100644 -index 000000000..d89362f46 ---- /dev/null -+++ b/tests/data/test1485 -@@ -0,0 +1,51 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Server: Someone -+Content-Length: 7 -+ -+123456 -+ -+ -+HTTP/1.1 200 OK -+Server: Someone -+Content-Length: 7 -+ -+123456 -+ -+ -+# Client-side -+ -+ -+http -+ -+ -+lib%TESTNUMBER -+ -+ -+get curlinfo on last header in callback -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+Accept: */* -+ -+ -+ -+ -diff --git a/tests/data/test1486 b/tests/data/test1486 -new file mode 100644 -index 000000000..e974b99e0 ---- /dev/null -+++ b/tests/data/test1486 -@@ -0,0 +1,32 @@ -+ -+ -+ -+source analysis -+docs -+--write-out -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+ -+Verify that write-out.md and tool_writeout.c are in sync -+ -+ -+ -+%SRCDIR/test1486.pl %SRCDIR -+ -+ -+ -+ -+ -+OK -+ -+ -+ -+ -diff --git a/tests/data/test1487 b/tests/data/test1487 -new file mode 100644 -index 000000000..a3eac5dba ---- /dev/null -+++ b/tests/data/test1487 -@@ -0,0 +1,54 @@ -+ -+ -+ -+HTTP -+HTTP GET -+-J -+ -+ -+ -+# -+ -+ -+HTTP/1.1 301 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange -+ -+12345 -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP GET with -J and Content-Disposition on 301 -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O --output-dir %LOGDIR -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+12345 -+ -+ -+ -+ -diff --git a/tests/data/test1488 b/tests/data/test1488 -new file mode 100644 -index 000000000..f987e151d ---- /dev/null -+++ b/tests/data/test1488 -@@ -0,0 +1,31 @@ -+ -+ -+ -+documentation -+symbols-in-versions -+manpages -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+ -+symbols-in-versions and manpages agree on added-in versions -+ -+ -+ -+%SRCDIR/test1488.pl %SRCDIR/.. ../include/curl -+ -+ -+ -+ -+ -+OK -+ -+ -+ -diff --git a/tests/data/test1489 b/tests/data/test1489 -new file mode 100644 -index 000000000..e1460bf5c ---- /dev/null -+++ b/tests/data/test1489 -@@ -0,0 +1,66 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+-D sent to stderr -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -D % -s -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+ -+ -+ -diff --git a/tests/data/test149 b/tests/data/test149 -index 404922b29..60d9089ae 100644 ---- a/tests/data/test149 -+++ b/tests/data/test149 -@@ -27,6 +27,9 @@ send away this contents - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test1490 b/tests/data/test1490 -new file mode 100644 -index 000000000..41d4c3a40 ---- /dev/null -+++ b/tests/data/test1490 -@@ -0,0 +1,43 @@ -+ -+ -+ -+FILE -+ -+ -+ -+# no Server-side -+ -+# Client-side -+ -+ -+file -+ -+ -+"upload" with file:// overwriting existing -+ -+ -+file://localhost%FILE_PWD/%LOGDIR/result%TESTNUMBER.txt -T %LOGDIR/upload%TESTNUMBER.txt -+ -+ -+data -+in -+file -+to -+write -+ -+ -+already existing -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+data -+in -+file -+to -+write -+ -+ -+ -diff --git a/tests/data/test1491 b/tests/data/test1491 -new file mode 100644 -index 000000000..84d4e94e0 ---- /dev/null -+++ b/tests/data/test1491 -@@ -0,0 +1,37 @@ -+ -+ -+ -+FILE -+ -+ -+ -+ -+ -+ -+# Client-side -+ -+ -+file -+ -+ -+file:// don't overwrite self with --skip-existing -+ -+ -+file://localhost%FILE_PWD/%LOGDIR/test%TESTNUMBER.txt -o %LOGDIR/test%TESTNUMBER.txt --skip-existing -+ -+ -+foo -+ bar -+bar -+ foo -+moo -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+Note: skips transfer, "%LOGDIR/test%TESTNUMBER.txt" exists locally -+ -+ -+ -diff --git a/tests/data/test1492 b/tests/data/test1492 -new file mode 100644 -index 000000000..2e7e1f32a ---- /dev/null -+++ b/tests/data/test1492 -@@ -0,0 +1,63 @@ -+ -+ -+ -+HTTP -+HTTP GET -+-J -+--show-headers -+ -+ -+ -+# -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 6 -+Connection: close -+Content-Jisposition: inline; filename="name%TESTNUMBER" -+Content-Type: text/html -+ -+12345 -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP GET with -J + --show-headers but no Content-Disposition: -+ -+ -+http://%HOSTIP:%HTTPPORT/junk%TESTNUMBER -J -O --show-headers --output-dir %LOGDIR -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /junk%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 6 -+Connection: close -+Content-Jisposition: inline; filename="name%TESTNUMBER" -+Content-Type: text/html -+ -+12345 -+ -+ -+ -+ -diff --git a/tests/data/test1501 b/tests/data/test1501 -index 195c17998..070ff7d97 100644 ---- a/tests/data/test1501 -+++ b/tests/data/test1501 -@@ -39,6 +39,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER/ - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 0 - -diff --git a/tests/data/test1521 b/tests/data/test1521 -index 21d51fdca..f62f58c5f 100644 ---- a/tests/data/test1521 -+++ b/tests/data/test1521 -@@ -26,5 +26,8 @@ unused - # - # Verify data after the test has been "shot" - -+ -+ok -+ - - -diff --git a/tests/data/test1538 b/tests/data/test1538 -index c0f038be4..111f2d8da 100644 ---- a/tests/data/test1538 -+++ b/tests/data/test1538 -@@ -37,9 +37,9 @@ e1: Unsupported protocol - e2: Failed initialization - e3: URL using bad/illegal format or missing URL - e4: A requested feature, protocol or option was not found built-in in this libcurl due to a build-time decision. --e5: Couldn't resolve proxy name --e6: Couldn't resolve host name --e7: Couldn't connect to server -+e5: Could not resolve proxy name -+e6: Could not resolve hostname -+e7: Could not connect to server - e8: Weird server reply - e9: Access denied to remote resource - e10: FTP: The server failed to connect to data port -@@ -47,11 +47,11 @@ e11: FTP: unknown PASS reply - e12: FTP: Accepting server connect has timed out - e13: FTP: unknown PASV reply - e14: FTP: unknown 227 response format --e15: FTP: can't figure out the host in the PASV response -+e15: FTP: cannot figure out the host in the PASV response - e16: Error in the HTTP2 framing layer --e17: FTP: couldn't set file type -+e17: FTP: could not set file type - e18: Transferred a partial file --e19: FTP: couldn't retrieve (RETR failed) the specified file -+e19: FTP: could not retrieve (RETR failed) the specified file - e20: Unknown error - e21: Quote command returned error - e22: HTTP response code said error -@@ -68,8 +68,8 @@ e32: Unknown error - e33: Requested range was not delivered by the server - e34: Internal problem setting up the POST - e35: SSL connect error --e36: Couldn't resume download --e37: Couldn't read a file:// file -+e36: Could not resume download -+e37: Could not read a file:// file - e38: LDAP: cannot bind - e39: LDAP: search failed - e40: Unknown error -@@ -91,7 +91,7 @@ e55: Failed sending data to the peer - e56: Failure when receiving data from the peer - e57: Unknown error - e58: Problem with the local SSL certificate --e59: Couldn't use specified SSL cipher -+e59: Could not use specified SSL cipher - e60: SSL peer certificate or SSH remote key was not OK - e61: Unrecognized or bad HTTP Content or Transfer-Encoding - e62: Unknown error -@@ -133,7 +133,8 @@ e97: proxy handshake error - e98: SSL Client Certificate required - e99: Unrecoverable error in select/poll - e100: A value or data field grew larger than allowed --e101: Unknown error -+e101: ECH attempted but failed -+e102: Unknown error - m-1: Please call curl_multi_perform() soon - m0: No error - m1: Invalid multi handle -diff --git a/tests/data/test1541 b/tests/data/test1541 -index 5094c3513..9b29f4353 100644 ---- a/tests/data/test1541 -+++ b/tests/data/test1541 -@@ -36,6 +36,7 @@ Transfer-Encoding: chunked - datad474 - CURLINFO_CONNECT_TIME_T on done is OK - CURLINFO_PRETRANSFER_TIME_T on done is OK -+CURLINFO_POSTTRANSFER_TIME_T on done is OK - CURLINFO_STARTTRANSFER_TIME_T on done is OK - CURLINFO_APPCONNECT_TIME_T on done is OK - CURLINFO_SPEED_DOWNLOAD_T on done is OK -diff --git a/tests/data/test1542 b/tests/data/test1542 -index f9806cda8..0454d76dd 100644 ---- a/tests/data/test1542 -+++ b/tests/data/test1542 -@@ -58,11 +58,11 @@ Accept: */* - == Info: Connection #0 to host %HOSTIP left intact - == Info: Connection #0 to host %HOSTIP left intact - == Info: Connection #0 to host %HOSTIP left intact --== Info: Closing connection -+== Info: shutting down connection #0 - == Info: Connection #1 to host %HOSTIP left intact - - --$_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) -+$_ = '' if (($_ !~ /left intact/) && ($_ !~ /(closing|shutting down) connection #\d+/)) - - - -diff --git a/tests/data/test1546 b/tests/data/test1546 -new file mode 100644 -index 000000000..0ec7093f7 ---- /dev/null -+++ b/tests/data/test1546 -@@ -0,0 +1,63 @@ -+ -+ -+ -+HTTP -+HTTP GET -+Transfer-Encoding -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Mon, 29 Nov 2004 21:56:53 GMT -+Server: Apache -+Transfer-Encoding: chunked, gzip -+ -+0 -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Mon, 29 Nov 2004 21:56:53 GMT -+Server: Apache -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+libz -+ -+ -+http -+ -+ -+HTTP transfer-encoding wrong order -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --tr-encoding -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+Connection: TE -+TE: gzip -+ -+ -+ -+61 -+ -+ -+ -diff --git a/tests/data/test1554 b/tests/data/test1554 -index c16195c17..8dc248b98 100644 ---- a/tests/data/test1554 -+++ b/tests/data/test1554 -@@ -19,67 +19,57 @@ Content-Length: 29 - run 1: foobar and so on fun! - - ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT - run 1: foobar and so on fun! ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT - run 1: foobar and so on fun! ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT - run 1: foobar and so on fun! ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock ---> Mutex lock --<- Mutex unlock -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+-> Mutex lock SHARE -+<- Mutex unlock SHARE -+-> Mutex lock SHARE -+-> Mutex lock CONNECT -+<- Mutex unlock CONNECT -+<- Mutex unlock SHARE - - - -diff --git a/tests/data/test1569 b/tests/data/test1569 -index 159a81391..24f16ee78 100644 ---- a/tests/data/test1569 -+++ b/tests/data/test1569 -@@ -40,6 +40,9 @@ lib%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test1570 b/tests/data/test1570 -index 713ab5ea7..e558b9bc3 100644 ---- a/tests/data/test1570 -+++ b/tests/data/test1570 -@@ -40,6 +40,9 @@ lib1569 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test159 b/tests/data/test159 -index fabcb4f98..cc183855a 100644 ---- a/tests/data/test159 -+++ b/tests/data/test159 -@@ -45,7 +45,7 @@ This is not the real page either! - NTLM - SSL - !SSPI --debug -+Debug - - - http -@@ -53,18 +53,9 @@ http - - HTTP with NTLM authorization when talking HTTP/1.0 (known to fail) - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER -u testuser:testpass --ntlm -0 - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test1592 b/tests/data/test1592 -index e0adc0efc..4dde49760 100644 ---- a/tests/data/test1592 -+++ b/tests/data/test1592 -@@ -29,9 +29,6 @@ http://a-site-never-accessed.example.org/%TESTNUMBER - - # Verify data after the test has been "shot" - -- --disable -- - - 0 - -diff --git a/tests/data/test1604 b/tests/data/test1604 -index 33e4e26c4..c8d19f548 100644 ---- a/tests/data/test1604 -+++ b/tests/data/test1604 -@@ -15,7 +15,7 @@ none - unittest - - --Test WIN32/MSDOS filename sanitization -+Test Windows/MS-DOS filename sanitization - - - -diff --git a/tests/data/test1616 b/tests/data/test1616 -new file mode 100644 -index 000000000..cce79c122 ---- /dev/null -+++ b/tests/data/test1616 -@@ -0,0 +1,22 @@ -+ -+ -+ -+unittest -+hash -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+unittest -+ -+ -+Internal hash_offt create/add/destroy testing, exercising clean functions -+ -+ -+ -diff --git a/tests/data/test1631 b/tests/data/test1631 -index 83bc83e42..f624c4142 100644 ---- a/tests/data/test1631 -+++ b/tests/data/test1631 -@@ -53,6 +53,9 @@ proxy - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - # The second CONNECT will be made to the dynamic port number the FTP server - # opens for us, so we can't compare with a known pre-existing number! -diff --git a/tests/data/test1632 b/tests/data/test1632 -index 18674d21b..919f2c528 100644 ---- a/tests/data/test1632 -+++ b/tests/data/test1632 -@@ -62,6 +62,9 @@ proxy - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - # The second and third CONNECT will be made to the dynamic port number the FTP - # server opens for us, so we can't compare with known pre-existing numbers! -diff --git a/tests/data/test165 b/tests/data/test165 -index d0353946a..39787db87 100644 ---- a/tests/data/test165 -+++ b/tests/data/test165 -@@ -28,16 +28,14 @@ Funny-head: yesyes - http - - --idn -+IDN - proxy -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - HTTP over proxy with IDN host name - -diff --git a/tests/data/test1655 b/tests/data/test1655 -index c5ec09129..6e7917031 100644 ---- a/tests/data/test1655 -+++ b/tests/data/test1655 -@@ -17,7 +17,7 @@ unittest - DoH - - --unit test for doh_encode -+unit test for doh_req_encode - - - -diff --git a/tests/data/test1656 b/tests/data/test1656 -new file mode 100644 -index 000000000..2fab21be6 ---- /dev/null -+++ b/tests/data/test1656 -@@ -0,0 +1,22 @@ -+ -+ -+ -+unittest -+Curl_x509_GTime2str -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+unittest -+ -+ -+Curl_x509_GTime2str unit tests -+ -+ -+ -diff --git a/tests/data/test1660 b/tests/data/test1660 -index f86126d19..4b6f9615c 100644 ---- a/tests/data/test1660 -+++ b/tests/data/test1660 -@@ -52,7 +52,7 @@ this.example [this.example]: 1548400797 - Input 12: error 43 - Input 13: error 43 - Input 14: error 43 --3.example.com [example.com]: 1569905261 includeSubDomains -+3.example.com [3.example.com]: 1569905261 includeSubDomains - 3.example.com [example.com]: 1569905261 includeSubDomains - foo.example.com [example.com]: 1569905261 includeSubDomains - 'foo.xample.com' is not HSTS -diff --git a/tests/data/test1662 b/tests/data/test1662 -index b2fbcce8b..7e72add94 100644 ---- a/tests/data/test1662 -+++ b/tests/data/test1662 -@@ -38,7 +38,7 @@ Funny-head: nono - - - Mime --debug -+Debug - - - http -diff --git a/tests/data/test1663 b/tests/data/test1663 -new file mode 100644 -index 000000000..160bfde3f ---- /dev/null -+++ b/tests/data/test1663 -@@ -0,0 +1,23 @@ -+ -+ -+ -+unittest -+interface -+bind -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+unittest -+ -+ -+unit tests for interface option parsing -+ -+ -+ -diff --git a/tests/data/test1683 b/tests/data/test1683 -index 581470dfc..66f41cea5 100644 ---- a/tests/data/test1683 -+++ b/tests/data/test1683 -@@ -39,11 +39,8 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER -o %LOGDIR/exist%TESTNUMBER --no-clobber - to stay the same - - --perl -e 'for my $i ((1..100)) { my $filename = "%LOGDIR/exist%TESTNUMBER.$i"; open(FH, ">", $filename) or die $!; print FH "to stay the same" ; close(FH) }' -+%PERL -e 'for my $i ((1..100)) { my $filename = "%LOGDIR/exist%TESTNUMBER.$i"; open(FH, ">", $filename) or die $!; print FH "to stay the same" ; close(FH) }' - -- --perl -e 'for my $i ((1..100)) { my $filename = "%LOGDIR/exist%TESTNUMBER.$i"; open(FH, "<", $filename) or die $!; ( eq "to stay the same" and eq "") or die "incorrect $filename" ; close(FH) }' -- - - - # -@@ -55,5 +52,8 @@ perl -e 'for my $i ((1..100)) { my $filename = "%LOGDIR/exist%TESTNUMBER.$i"; op - - to stay the same - -+ -+%PERL -e 'for my $i ((1..100)) { my $filename = "%LOGDIR/exist%TESTNUMBER.$i"; open(FH, "<", $filename) or die $!; ( eq "to stay the same" and eq "") or die "incorrect $filename" ; close(FH) }' -+ - - -diff --git a/tests/data/test1700 b/tests/data/test1700 -index 8d1fff580..be5644db5 100644 ---- a/tests/data/test1700 -+++ b/tests/data/test1700 -@@ -42,7 +42,6 @@ Content-Type: text/html - h2c - - --http - http/2 - - -diff --git a/tests/data/test1701 b/tests/data/test1701 -index c81862aeb..469026d79 100644 ---- a/tests/data/test1701 -+++ b/tests/data/test1701 -@@ -33,7 +33,6 @@ Funny-head: yesyes - h2c - - --http - http/2 - - -diff --git a/tests/data/test1702 b/tests/data/test1702 -index ced2ca06c..ce4a1c04d 100644 ---- a/tests/data/test1702 -+++ b/tests/data/test1702 -@@ -32,7 +32,6 @@ Funny-head: yesyes - h2c - - --http - http/2 - - -diff --git a/tests/data/test1704 b/tests/data/test1704 -index a8f285eea..a8740187f 100644 ---- a/tests/data/test1704 -+++ b/tests/data/test1704 -@@ -54,7 +54,7 @@ User-Agent: curl/%VERSION - Accept: */* - Connection: Upgrade, HTTP2-Settings - Upgrade: h2c --HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA -+HTTP2-Settings: AAMAAABkAAQAAQAAAAIAAAAA - - - -diff --git a/tests/data/test1705 b/tests/data/test1705 -new file mode 100644 -index 000000000..6736d928c ---- /dev/null -+++ b/tests/data/test1705 -@@ -0,0 +1,302 @@ -+ -+ -+ -+script -+documentation -+managen -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+ -+managen makes manpage -+ -+ -+ -+_header.md -+%options -+_footer.md -+ -+ -+ -+ -+ -+# DESCRIPTION -+ -+**curl** is a tool for transferring data from or to a server using URLs. It -+supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, -+IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, -+SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. -+ -+curl is powered by libcurl for all transfer-related features. See -+*libcurl(3)* for details. -+ -+ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Short: v -+Long: fakeitreal -+Mutexed: trace trace-ascii -+Help: Make the operation more talkative -+Category: important verbose global -+Added: 4.0 -+Multi: boolean -+Scope: global -+See-also: -+ - include -+ - silent -+ - trace -+ - trace-ascii -+Example: -+ - --verbose $URL -+--- -+ -+# `--verbose` -+ -+Makes curl verbose during the operation. Useful for debugging and seeing -+what's going on under the hood. A line starting with \> means header data sent -+by curl, \< means header data received by curl that is hidden in normal cases, -+and a line starting with * means additional info provided by curl. -+ -+If you only want HTTP headers in the output, --include or --dump-header might -+be more suitable options. -+ -+If you think this option still does not give you enough details, consider using -+--trace or --trace-ascii instead. -+ -+Note that verbose output of curl activities and network traffic might contain -+sensitive data, including usernames, credentials or secret data content. Be -+aware and be careful when sharing trace logs with others. -+ -+End with a quote -+ -+ hello -+ -+ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: proto -+Arg: -+Help: Enable/disable PROTOCOLS -+Added: 7.20.2 -+Category: connection curl -+Multi: single -+See-also: -+ - fakeitreal -+ - proto-default -+Example: -+ - --proto =http,https,sftp $URL -+--- -+ -+# `--proto` -+ -+Limit what protocols to allow for transfers. Protocols are evaluated left to -+right, are comma separated, and are each a protocol name or 'all', optionally -+prefixed by zero or more modifiers. Available modifiers are: -+ -+## + -+Permit this protocol in addition to protocols already permitted (this is -+the default if no modifier is used). -+ -+## - -+Deny this protocol, removing it from the list of protocols already permitted. -+ -+## = -+Permit only this protocol (ignoring the list already permitted), though -+subject to later modification by subsequent entries in the comma separated -+list. -+ -+## -+ -+For example: --proto -ftps uses the default protocols, but disables ftps -+ -+--proto -all,https,+http only enables http and https -+ -+--proto =http,https also only enables http and https -+ -+Unknown and disabled protocols produce a warning. This allows scripts to -+safely rely on being able to disable potentially dangerous protocols, without -+relying upon support for that protocol being built into curl to avoid an error. -+ -+This option can be used multiple times, in which case the effect is the same -+as concatenating the protocols into one instance of the option. -+ -+ -+ -+ -+# PROXY PROTOCOL PREFIXES -+The proxy string may be specified with a protocol:// prefix to specify -+alternative proxy protocols. (Added in 7.21.7) -+ -+If no protocol is specified in the proxy string or if the string does not -+match a supported one, the proxy is treated as an HTTP proxy. -+ -+The supported proxy protocol prefixes are as follows: -+## http:// -+Makes it use it as an HTTP proxy. The default if no scheme prefix is used. -+## https:// -+Makes it treated as an **HTTPS** proxy. -+## socks4:// -+Makes it the equivalent of --socks4 -+## socks4a:// -+Makes it the equivalent of --socks4a -+## socks5:// -+Makes it the equivalent of --socks5 -+## socks5h:// -+Makes it the equivalent of --socks5-hostname -+ -+ -+ -+%SRCDIR/../scripts/managen -d %LOGDIR -I %SRCDIR/../include mainpage option1.md option2.md -+ -+ -+ -+ -+ -+option1.md:19:1:WARN: see-also a non-existing option: include -+option1.md:19:1:WARN: see-also a non-existing option: silent -+option1.md:19:1:WARN: see-also a non-existing option: trace -+option1.md:19:1:WARN: see-also a non-existing option: trace-ascii -+WARN: option1.md mutexes a non-existing option: trace -+WARN: option1.md mutexes a non-existing option: trace-ascii -+option2.md:15:1:WARN: see-also a non-existing option: proto-default -+ -+ -+.\" ************************************************************************** -+.\" * _ _ ____ _ -+.\" * Project ___| | | | _ \| | -+.\" * / __| | | | |_) | | -+.\" * | (__| |_| | _ <| |___ -+.\" * \___|\___/|_| \_\_____| -+.\" * -+.\" * Copyright (C) Daniel Stenberg, , 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 -+.\" * -+.\" ************************************************************************** -+.\" -+.\" DO NOT EDIT. Generated by the curl project managen manpage generator. -+.\" -+.TH curl 1 "%DATE" "curl %VERNUM" "curl Manual" -+.SH DESCRIPTION -+\fBcurl\fP is a tool for transferring data from or to a server using URLs. It -+supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, -+IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, -+SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. -+ -+curl is powered by libcurl for all transfer\-related features. See -+\fIlibcurl(3)\fP for details. -+.IP "\-v, \-\-fakeitreal" -+Makes curl verbose during the operation. Useful for debugging and seeing -+what\(aqs going on under the hood. A line starting with > means header data sent -+by curl, < means header data received by curl that is hidden in normal cases, -+and a line starting with * means additional info provided by curl. -+ -+If you only want HTTP headers in the output, \fI\-\-include\fP or \fI\-\-dump\-header\fP might -+be more suitable options. -+ -+If you think this option still does not give you enough details, consider using -+\fI\-\-trace\fP or \fI\-\-trace\-ascii\fP instead. -+ -+Note that verbose output of curl activities and network traffic might contain -+sensitive data, including usernames, credentials or secret data content. Be -+aware and be careful when sharing trace logs with others. -+ -+End with a quote -+ -+.nf -+hello -+.fi -+ -+This option is global and does not need to be specified for each use of --next. -+ -+Providing --fakeitreal multiple times has no extra effect. -+Disable it again with \-\-no-fakeitreal. -+ -+Example: -+.nf -+curl --verbose https://example.com -+.fi -+ -+This option is mutually exclusive with \fI\-\-trace\fP and \fI\-\-trace\-ascii\fP. -+See also \fI\-\-include\fP, \fI\-\-silent\fP, \fI\-\-trace\fP and \fI\-\-trace\-ascii\fP. -+.IP "\-\-proto " -+Limit what protocols to allow for transfers. Protocols are evaluated left to -+right, are comma separated, and are each a protocol name or \(aqall\(aq, optionally -+prefixed by zero or more modifiers. Available modifiers are: -+.RS -+.IP + -+Permit this protocol in addition to protocols already permitted (this is -+the default if no modifier is used). -+.IP - -+Deny this protocol, removing it from the list of protocols already permitted. -+.IP = -+Permit only this protocol (ignoring the list already permitted), though -+subject to later modification by subsequent entries in the comma separated -+list. -+.RE -+.IP -+For example: \fI\-\-proto\fP \-ftps uses the default protocols, but disables ftps -+ -+\fI\-\-proto\fP \-all,https,+http only enables http and https -+ -+\fI\-\-proto\fP =http,https also only enables http and https -+ -+Unknown and disabled protocols produce a warning. This allows scripts to -+safely rely on being able to disable potentially dangerous protocols, without -+relying upon support for that protocol being built into curl to avoid an error. -+ -+This option can be used multiple times, in which case the effect is the same -+as concatenating the protocols into one instance of the option. -+ -+If --proto is provided several times, the last set value is used. -+ -+Example: -+.nf -+curl --proto =http,https,sftp https://example.com -+.fi -+ -+See also \fI-v, \-\-fakeitreal\fP and \fI\-\-proto\-default\fP. -+.SH PROXY PROTOCOL PREFIXES -+The proxy string may be specified with a protocol:// prefix to specify -+alternative proxy protocols. -+ -+If no protocol is specified in the proxy string or if the string does not -+match a supported one, the proxy is treated as an HTTP proxy. -+ -+The supported proxy protocol prefixes are as follows: -+.IP http:// -+Makes it use it as an HTTP proxy. The default if no scheme prefix is used. -+.IP https:// -+Makes it treated as an \fBHTTPS\fP proxy. -+.IP socks4:// -+Makes it the equivalent of \fI\-\-socks4\fP -+.IP socks4a:// -+Makes it the equivalent of \fI\-\-socks4a\fP -+.IP socks5:// -+Makes it the equivalent of \fI\-\-socks5\fP -+.IP socks5h:// -+Makes it the equivalent of \fI\-\-socks5\-hostname\fP -+ -+ -+ -+ -diff --git a/tests/data/test1706 b/tests/data/test1706 -new file mode 100644 -index 000000000..7752ecf31 ---- /dev/null -+++ b/tests/data/test1706 -@@ -0,0 +1,288 @@ -+ -+ -+ -+script -+documentation -+managen -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+ -+managen makes ASCII page -+ -+ -+ -+_header.md -+%options -+_footer.md -+ -+ -+ -+ -+ -+# DESCRIPTION -+ -+**curl** is a tool for transferring data from or to a server using URLs. It -+supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, -+IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, -+SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. -+ -+curl is powered by libcurl for all transfer-related features. See -+*libcurl(3)* for details. -+ -+ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Short: v -+Long: fakeitreal -+Mutexed: trace trace-ascii -+Help: Make the operation more talkative -+Category: important verbose global -+Added: 4.0 -+Multi: boolean -+Scope: global -+See-also: -+ - include -+ - silent -+ - trace -+ - trace-ascii -+Example: -+ - --verbose $URL -+--- -+ -+# `--verbose` -+ -+Makes curl verbose during the operation. Useful for debugging and seeing -+what's going on under the hood. A line starting with \> means header data sent -+by curl, \< means header data received by curl that is hidden in normal cases, -+and a line starting with * means additional info provided by curl. -+ -+If you only want HTTP headers in the output, --include or --dump-header might -+be more suitable options. -+ -+If you think this option still does not give you enough details, consider using -+--trace or --trace-ascii instead. -+ -+Note that verbose output of curl activities and network traffic might contain -+sensitive data, including usernames, credentials or secret data content. Be -+aware and be careful when sharing trace logs with others. -+ -+ -+--- -+c: Copyright (C) Daniel Stenberg, , et al. -+SPDX-License-Identifier: curl -+Long: proto -+Arg: -+Help: Enable/disable PROTOCOLS -+Added: 7.20.2 -+Category: connection curl -+Multi: single -+See-also: -+ - fakeitreal -+ - proto-default -+Example: -+ - --proto =http,https,sftp $URL -+--- -+ -+# `--proto` -+ -+Limit what protocols to allow for transfers. Protocols are evaluated left to -+right, are comma separated, and are each a protocol name or 'all', optionally -+prefixed by zero or more modifiers. Available modifiers are: -+ -+## + -+Permit this protocol in addition to protocols already permitted (this is -+the default if no modifier is used). -+ -+## - -+Deny this protocol, removing it from the list of protocols already permitted. -+ -+## = -+Permit only this protocol (ignoring the list already permitted), though -+subject to later modification by subsequent entries in the comma separated -+list. -+ -+## -+ -+For example: --proto -ftps uses the default protocols, but disables ftps -+ -+--proto -all,https,+http only enables http and https -+ -+--proto =http,https also only enables http and https -+ -+Unknown and disabled protocols produce a warning. This allows scripts to -+safely rely on being able to disable potentially dangerous protocols, without -+relying upon support for that protocol being built into curl to avoid an error. -+ -+This option can be used multiple times, in which case the effect is the same -+as concatenating the protocols into one instance of the option. -+ -+ -+ -+ -+# PROXY PROTOCOL PREFIXES -+The proxy string may be specified with a protocol:// prefix to specify -+alternative proxy protocols. (Added in 7.21.7) -+ -+If no protocol is specified in the proxy string or if the string does not -+match a supported one, the proxy is treated as an HTTP proxy. -+ -+The supported proxy protocol prefixes are as follows: -+## http:// -+Makes it use it as an HTTP proxy. The default if no scheme prefix is used. -+## https:// -+Makes it treated as an **HTTPS** proxy. -+## socks4:// -+Makes it the equivalent of --socks4 -+## socks4a:// -+Makes it the equivalent of --socks4a -+## socks5:// -+Makes it the equivalent of --socks5 -+## socks5h:// -+Makes it the equivalent of --socks5-hostname -+ -+ -+ -+%SRCDIR/../scripts/managen -d %LOGDIR ascii option1.md option2.md -+ -+ -+ -+ -+ -+option1.md:19:1:WARN: see-also a non-existing option: include -+option1.md:19:1:WARN: see-also a non-existing option: silent -+option1.md:19:1:WARN: see-also a non-existing option: trace -+option1.md:19:1:WARN: see-also a non-existing option: trace-ascii -+WARN: option1.md mutexes a non-existing option: trace -+WARN: option1.md mutexes a non-existing option: trace-ascii -+option2.md:15:1:WARN: see-also a non-existing option: proto-default -+ -+ -+DESCRIPTION -+ -+ curl is a tool for transferring data from or to a server using URLs. It -+ supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, -+ HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, -+ SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. -+ -+ curl is powered by libcurl for all transfer-related features. See -+ libcurl(3) for details. -+ -+ -v, --fakeitreal -+ Makes curl verbose during the operation. Useful for debugging and -+ seeing what's going on under the hood. A line starting with > -+ means header data sent by curl, < means header data received by -+ curl that is hidden in normal cases, and a line starting with * -+ means additional info provided by curl. -+ -+ If you only want HTTP headers in the output, --include or -+ --dump-header might be more suitable options. -+ -+ If you think this option still does not give you enough details, -+ consider using --trace or --trace-ascii instead. -+ -+ Note that verbose output of curl activities and network traffic -+ might contain sensitive data, including usernames, credentials or -+ secret data content. Be aware and be careful when sharing trace -+ logs with others. -+ -+ This option is global and does not need to be specified for each -+ use of --next. Providing --fakeitreal multiple times has no extra -+ effect. Disable it again with --no-fakeitreal. -+ -+ Example: -+ curl --verbose https://example.com -+ -+ This option is mutually exclusive with --trace and --trace-ascii. -+ See also --include, --silent, --trace and --trace-ascii. -+ -+ --proto -+ Limit what protocols to allow for transfers. Protocols are -+ evaluated left to right, are comma separated, and are each a -+ protocol name or 'all', optionally prefixed by zero or more -+ modifiers. Available modifiers are: -+ -+ + -+ -+ Permit this protocol in addition to protocols already -+ permitted (this is the default if no modifier is used). -+ -+ - -+ -+ Deny this protocol, removing it from the list of protocols -+ already permitted. -+ -+ = -+ -+ Permit only this protocol (ignoring the list already -+ permitted), though subject to later modification by subsequent -+ entries in the comma separated list. For example: --proto -+ -ftps uses the default protocols, but disables ftps -+ -+ --proto -all,https,+http only enables http and https -+ -+ --proto =http,https also only enables http and https -+ -+ Unknown and disabled protocols produce a warning. This allows -+ scripts to safely rely on being able to disable potentially -+ dangerous protocols, without relying upon support for that -+ protocol being built into curl to avoid an error. -+ -+ This option can be used multiple times, in which case the -+ effect is the same as concatenating the protocols into one -+ instance of the option. -+ -+ If --proto is provided several times, the last set value is used. -+ -+ Example: -+ curl --proto =http,https,sftp https://example.com -+ -+ See also --fakeitreal and --proto-default. -+ -+PROXY PROTOCOL PREFIXES -+ -+ The proxy string may be specified with a protocol:// prefix to specify -+ alternative proxy protocols. -+ -+ If no protocol is specified in the proxy string or if the string does not -+ match a supported one, the proxy is treated as an HTTP proxy. -+ -+ The supported proxy protocol prefixes are as follows: -+ -+ http:// -+ -+ Makes it use it as an HTTP proxy. The default if no scheme prefix is -+ used. -+ -+ https:// -+ -+ Makes it treated as an HTTPS proxy. -+ -+ socks4:// -+ -+ Makes it the equivalent of --socks4 -+ -+ socks4a:// -+ -+ Makes it the equivalent of --socks4a -+ -+ socks5:// -+ -+ Makes it the equivalent of --socks5 -+ -+ socks5h:// -+ -+ Makes it the equivalent of --socks5-hostname -+ -+ -+ -+ -+ -diff --git a/tests/data/test1707 b/tests/data/test1707 -new file mode 100644 -index 000000000..f18749068 ---- /dev/null -+++ b/tests/data/test1707 -@@ -0,0 +1,27 @@ -+ -+ -+ -+curl -+ -+ -+ -+# -+# Client-side -+ -+ -+manual -+ -+ -+none -+ -+ -+ -+Verify curl -h --insecure -+ -+ -+ -+%SRCDIR/test1707.pl %CURL --insecure %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt -+ -+ -+ -+ -diff --git a/tests/data/test1708 b/tests/data/test1708 -new file mode 100644 -index 000000000..ab59e71fa ---- /dev/null -+++ b/tests/data/test1708 -@@ -0,0 +1,27 @@ -+ -+ -+ -+curl -+ -+ -+ -+# -+# Client-side -+ -+ -+manual -+ -+ -+none -+ -+ -+ -+Verify curl -h -F -+ -+ -+ -+%SRCDIR/test1707.pl %CURL -F %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt -+ -+ -+ -+ -diff --git a/tests/data/test1709 b/tests/data/test1709 -new file mode 100644 -index 000000000..8482ba49a ---- /dev/null -+++ b/tests/data/test1709 -@@ -0,0 +1,32 @@ -+ -+ -+ -+curl -+ -+ -+ -+# -+# Client-side -+ -+ -+manual -+ -+ -+none -+ -+ -+ -+Verify curl -h --badone -+ -+ -+ -+-h --badone -+ -+ -+ -+ -+ -+Incorrect option name to show help for, see curl -h -+ -+ -+ -diff --git a/tests/data/test1710 b/tests/data/test1710 -new file mode 100644 -index 000000000..7356355e4 ---- /dev/null -+++ b/tests/data/test1710 -@@ -0,0 +1,27 @@ -+ -+ -+ -+curl -+ -+ -+ -+# -+# Client-side -+ -+ -+manual -+ -+ -+none -+ -+ -+ -+Verify curl -h --no-clobber -+ -+ -+ -+%SRCDIR/test1707.pl %CURL --no-clobber %LOGDIR/help%TESTNUMBER ../docs/cmdline-opts/curl.txt -+ -+ -+ -+ -diff --git a/tests/data/test173 b/tests/data/test173 -index a4bffcd9a..5e6f75169 100644 ---- a/tests/data/test173 -+++ b/tests/data/test173 -@@ -31,7 +31,7 @@ http - HTTP RFC1867-formpost a file from stdin with "faked" filename - - --http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER -F field1=contents1 -F "fileupload=@-;filename=/dev/null;type=text/x-null;format=x-curl" -+http://%HOSTIP:%HTTPPORT/we/want/%TESTNUMBER -F field1=contents1 -F "fileupload=@-;filename=%DEV_NULL;type=text/x-null;format=x-curl" - - - -@@ -64,7 +64,7 @@ Content-Disposition: form-data; name="field1" - - contents1 - ------------------------------5dbea401cd8c --Content-Disposition: form-data; name="fileupload"; filename="/dev/null" -+Content-Disposition: form-data; name="fileupload"; filename="%DEV_NULL" - Content-Type: text/x-null;format=x-curl - - line1 -diff --git a/tests/data/test1800 b/tests/data/test1800 -index de315d063..b1fd8021a 100644 ---- a/tests/data/test1800 -+++ b/tests/data/test1800 -@@ -49,7 +49,7 @@ User-Agent: curl/%VERSION - Accept: */* - Connection: Upgrade, HTTP2-Settings - Upgrade: %H2CVER --HTTP2-Settings: AAMAAABkAAQAoAAAAAIAAAAA -+HTTP2-Settings: AAMAAABkAAQAAQAAAAIAAAAA - - - -diff --git a/tests/data/test182 b/tests/data/test182 -index cb1e4f0c2..b49f10f85 100644 ---- a/tests/data/test182 -+++ b/tests/data/test182 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test190 b/tests/data/test190 -index b0328fdcb..033152f38 100644 ---- a/tests/data/test190 -+++ b/tests/data/test190 -@@ -27,7 +27,7 @@ ftp - FTP download with strict timeout and slow CWD - - --ftp://%HOSTIP:%FTPPORT/path/to/file/%TESTNUMBER -m %FTPTIME2 -+ftp://%HOSTIP:%FTPPORT/path/to/file/%TESTNUMBER -m 10 - - - -diff --git a/tests/data/test1901 b/tests/data/test1901 -new file mode 100644 -index 000000000..143a5f165 ---- /dev/null -+++ b/tests/data/test1901 -@@ -0,0 +1,60 @@ -+ -+ -+ -+HTTP -+HTTP POST -+CURLOPT_READFUNCTION -+ -+ -+ -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Content-Length: 6 -+Content-Type: text/html -+ -+-foo- -+ -+ -+ -+# Client-side -+ -+ -+http -+ -+ -+ -+Chunked HTTP POST from callback with CURLOPT_POSTFIELDSIZE set -+ -+ -+lib%TESTNUMBER -+ -+ -+ -+http://%HOSTIP:%HTTPPORT/boom -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+POST /boom HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+Accept: */* -+Transfer-Encoding: chunked -+Content-Type: application/x-www-form-urlencoded -+ -+3 -+one -+3 -+two -+5 -+three -+4 -+four -+0 -+ -+ -+ -+ -diff --git a/tests/data/test1908 b/tests/data/test1908 -index 4ec55ed23..e4ec639cd 100644 ---- a/tests/data/test1908 -+++ b/tests/data/test1908 -@@ -37,7 +37,7 @@ http - # require debug so that alt-svc can work over plain old HTTP - - alt-svc --debug -+Debug - - - alt-svc cache save after resetting the handle -diff --git a/tests/data/test191 b/tests/data/test191 -index 029369363..749a34ec9 100644 ---- a/tests/data/test191 -+++ b/tests/data/test191 -@@ -27,6 +27,9 @@ FTP URL with ?-letters in username and password - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER use?r - PASS pass?word -diff --git a/tests/data/test1915 b/tests/data/test1915 -index 0af542114..34a2881ef 100644 ---- a/tests/data/test1915 -+++ b/tests/data/test1915 -@@ -21,7 +21,6 @@ http - none - - --# require debug so that alt-svc can work over plain old HTTP - - HSTS read/write callbacks - -diff --git a/tests/data/test1933 b/tests/data/test1933 -index 3f3e8ac2c..456c8cfa0 100644 ---- a/tests/data/test1933 -+++ b/tests/data/test1933 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1934 b/tests/data/test1934 -index a131df49e..f0235a7d3 100644 ---- a/tests/data/test1934 -+++ b/tests/data/test1934 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1935 b/tests/data/test1935 -index d39a86471..b36e1fade 100644 ---- a/tests/data/test1935 -+++ b/tests/data/test1935 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1936 b/tests/data/test1936 -index a0d38403b..e937235d4 100644 ---- a/tests/data/test1936 -+++ b/tests/data/test1936 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1937 b/tests/data/test1937 -index ca1214b83..fc2d48c58 100644 ---- a/tests/data/test1937 -+++ b/tests/data/test1937 -@@ -36,7 +36,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1938 b/tests/data/test1938 -index 565a54ffe..ed24261b2 100644 -Binary files a/tests/data/test1938 and b/tests/data/test1938 differ -diff --git a/tests/data/test1955 b/tests/data/test1955 -index 27bb466c7..61b5100bd 100644 ---- a/tests/data/test1955 -+++ b/tests/data/test1955 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1956 b/tests/data/test1956 -index 76aaa93ab..fbde6d718 100644 ---- a/tests/data/test1956 -+++ b/tests/data/test1956 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1957 b/tests/data/test1957 -index add27db0f..39f11ac8b 100644 ---- a/tests/data/test1957 -+++ b/tests/data/test1957 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1958 b/tests/data/test1958 -index c54b17962..99989097e 100644 ---- a/tests/data/test1958 -+++ b/tests/data/test1958 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1959 b/tests/data/test1959 -index 2be813b08..e3d080509 100644 ---- a/tests/data/test1959 -+++ b/tests/data/test1959 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test196 b/tests/data/test196 -index b1a684f10..c72cbebf4 100644 ---- a/tests/data/test196 -+++ b/tests/data/test196 -@@ -22,7 +22,7 @@ ftp - FTP transient error, retry request once - - --ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --retry 1 -+ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --retry 1 -w '%{num_retries}\n' - - - -@@ -38,5 +38,8 @@ PASS ftp@example.com - USER anonymous - PASS ftp@example.com - -+ -+1 -+ - - -diff --git a/tests/data/test1970 b/tests/data/test1970 -index 1fbe60b45..9ed1a1e64 100644 ---- a/tests/data/test1970 -+++ b/tests/data/test1970 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1971 b/tests/data/test1971 -index c311d176f..a0b20c4d7 100644 ---- a/tests/data/test1971 -+++ b/tests/data/test1971 -@@ -28,7 +28,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1972 b/tests/data/test1972 -index 39e574747..901aae29e 100644 ---- a/tests/data/test1972 -+++ b/tests/data/test1972 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1973 b/tests/data/test1973 -index 559fd5fc7..af64b90e0 100644 ---- a/tests/data/test1973 -+++ b/tests/data/test1973 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1974 b/tests/data/test1974 -index 9b5bb8475..ee88bec74 100644 ---- a/tests/data/test1974 -+++ b/tests/data/test1974 -@@ -35,7 +35,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1975 b/tests/data/test1975 -index 09256de04..277e35edd 100644 ---- a/tests/data/test1975 -+++ b/tests/data/test1975 -@@ -28,7 +28,7 @@ http - # this relies on the debug feature which allow to set the time - - SSL --debug -+Debug - crypto - - -diff --git a/tests/data/test1976 b/tests/data/test1976 -new file mode 100644 -index 000000000..7c04bc655 ---- /dev/null -+++ b/tests/data/test1976 -@@ -0,0 +1,60 @@ -+ -+ -+ -+HTTP -+CURLOPT_AWS_SIGV4 -+ -+ -+ -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Thu, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 0 -+ -+ -+ -+ -+# Client-side -+ -+ -+http -+ -+ -+SSL -+Debug -+crypto -+ -+ -+HTTP AWS_SIGV4 canonical request header sorting test -+ -+ -+-X PUT -H "X-Amz-Meta-Test-Two: test2" -H "x-amz-meta-test: test" --aws-sigv4 "aws:amz:us-east-1:s3" -u "xxx:yyy" http://%HOSTIP:%HTTPPORT/%TESTNUMBER -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+^User-Agent:.* -+^Content-Length:.* -+^Accept:.* -+ -+ -+# Strip the actual signature. We only care about header order in this test -+s/Signature=[a-f0-9]{64}/Signature=stripped/ -+ -+ -+PUT /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+Authorization: AWS4-HMAC-SHA256 Credential=xxx/19700101/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-meta-test;x-amz-meta-test-two, Signature=stripped -+X-Amz-Date: 19700101T000000Z -+x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 -+X-Amz-Meta-Test-Two: test2 -+x-amz-meta-test: test -+ -+ -+ -+ -diff --git a/tests/data/test2000 b/tests/data/test2000 -index 032bf5b1b..ee2e50734 100644 ---- a/tests/data/test2000 -+++ b/tests/data/test2000 -@@ -46,6 +46,9 @@ moo - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test2001 b/tests/data/test2001 -index de1673531..39eb1ff9d 100644 ---- a/tests/data/test2001 -+++ b/tests/data/test2001 -@@ -63,6 +63,9 @@ moo - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - GET /%TESTNUMBER0001 HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test2002 b/tests/data/test2002 -index 4b2b4fef6..7a581a5cb 100644 ---- a/tests/data/test2002 -+++ b/tests/data/test2002 -@@ -73,6 +73,9 @@ moo - # Verify data after the test has been "shot" - - -+QUIT -+ -+ - ^timeout = [5-6]$ - - -diff --git a/tests/data/test2003 b/tests/data/test2003 -index dcd862178..2475bbe32 100644 ---- a/tests/data/test2003 -+++ b/tests/data/test2003 -@@ -73,6 +73,9 @@ moo - # Verify data after the test has been "shot" - - -+QUIT -+ -+ - ^timeout = [5-6]$ - - -diff --git a/tests/data/test2004 b/tests/data/test2004 -index 404b354ce..a9cb75f79 100644 ---- a/tests/data/test2004 -+++ b/tests/data/test2004 -@@ -72,8 +72,5 @@ for several protocols - Test data file - for tftp test - -- --disable -- - - -diff --git a/tests/data/test201 b/tests/data/test201 -index aff9ca2b8..a413ca3ff 100644 ---- a/tests/data/test201 -+++ b/tests/data/test201 -@@ -21,7 +21,7 @@ file - missing file:// file - - --file://localhost/%PWD/%LOGDIR/non-existent-file.txt -+file://localhost/%FILE_PWD/%LOGDIR/non-existent-file.txt - - - -diff --git a/tests/data/test2023 b/tests/data/test2023 -index e395ece9d..759e68280 100644 ---- a/tests/data/test2023 -+++ b/tests/data/test2023 -@@ -112,18 +112,9 @@ libauthretry - - HTTP authorization retry (Basic) - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER basic basic - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test2024 b/tests/data/test2024 -index 07bf931a2..915f76919 100644 ---- a/tests/data/test2024 -+++ b/tests/data/test2024 -@@ -126,18 +126,9 @@ libauthretry - - HTTP authorization retry (Basic switching to Digest) - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER basic digest - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test2026 b/tests/data/test2026 -index 81d252a30..96e2ad496 100644 ---- a/tests/data/test2026 -+++ b/tests/data/test2026 -@@ -162,18 +162,9 @@ libauthretry - - HTTP authorization retry (Digest switching to Basic) - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER digest basic - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test2027 b/tests/data/test2027 -index 0a9338777..45baa64bc 100644 ---- a/tests/data/test2027 -+++ b/tests/data/test2027 -@@ -185,18 +185,9 @@ libauthretry - - HTTP authorization retry (Digest) - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - http://%HOSTIP:%HTTPPORT/%TESTNUMBER digest digest - -- --chkhostname curlhost -- - - - # Verify data after the test has been "shot" -diff --git a/tests/data/test2033 b/tests/data/test2033 -index 2a9f90091..01056594d 100644 ---- a/tests/data/test2033 -+++ b/tests/data/test2033 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,16 +36,12 @@ https Server-localhost-sv.pem - simple HTTPS GET with DER public key pinning (Schannel variant) - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.der --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.der --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2034 b/tests/data/test2034 -index 5192cb73e..68963bd5b 100644 ---- a/tests/data/test2034 -+++ b/tests/data/test2034 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - !Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,12 +36,8 @@ https Server-localhost-sv.pem - simple HTTPS GET with DER public key pinning - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.der https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.der https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2035 b/tests/data/test2035 -index b17cddd56..66fa5874c 100644 ---- a/tests/data/test2035 -+++ b/tests/data/test2035 -@@ -18,6 +18,7 @@ PEM certificate - - SSL - SSLpinning -+local-http - - - https Server-localhost-sv.pem -@@ -26,12 +27,8 @@ https Server-localhost-sv.pem - HTTPS wrong DER pinnedpubkey but right CN - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.der https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.der https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2037 b/tests/data/test2037 -index 96406410a..50c4c72e9 100644 ---- a/tests/data/test2037 -+++ b/tests/data/test2037 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - !Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,12 +36,8 @@ https Server-localhost-sv.pem - simple HTTPS GET with PEM public key pinning - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.pem https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.pem https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2038 b/tests/data/test2038 -index 6cd91d623..2ec01af65 100644 ---- a/tests/data/test2038 -+++ b/tests/data/test2038 -@@ -18,6 +18,7 @@ PEM certificate - - SSL - SSLpinning -+local-http - - - https Server-localhost-sv.pem -@@ -26,12 +27,8 @@ https Server-localhost-sv.pem - HTTPS wrong PEM pinnedpubkey but right CN - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pem https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pem https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2039 b/tests/data/test2039 -index fdb61ed02..05f23ab74 100644 ---- a/tests/data/test2039 -+++ b/tests/data/test2039 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -50,6 +48,9 @@ machine %HOSTIP login user2 password passwd2 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER userdef - PASS passwddef -diff --git a/tests/data/test2041 b/tests/data/test2041 -index b7b461e0d..e4ee415e9 100644 ---- a/tests/data/test2041 -+++ b/tests/data/test2041 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - !Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,12 +36,8 @@ https Server-localhost-sv.pem - simple HTTPS GET with base64-sha256 public key pinning - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//AAUDLk4c98xcFUDvA9i/MnA9HuO03IPi15r+Cx9OXnc= https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//%sha256b64file[%SRCDIR/certs/Server-localhost-sv.pub.der]sha256b64file% https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2042 b/tests/data/test2042 -index 594a7e460..13a0fad24 100644 ---- a/tests/data/test2042 -+++ b/tests/data/test2042 -@@ -18,6 +18,7 @@ PEM certificate - - SSL - SSLpinning -+local-http - - - https Server-localhost-sv.pem -@@ -26,12 +27,8 @@ https Server-localhost-sv.pem - HTTPS wrong base64-sha256 pinnedpubkey but right CN - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//bSIggTf+ikMG0CtmDlpMVBd7yi7H1md4URogRPqerso= https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//bSIggTf+ikMG0CtmDlpMVBd7yi7H1md4URogRPqerso= https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2046 b/tests/data/test2046 -index fc5ddca84..c0d3a0e82 100644 ---- a/tests/data/test2046 -+++ b/tests/data/test2046 -@@ -39,15 +39,13 @@ OK - http - - --idn -+IDN -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - Connection reuse with IDN host name - -diff --git a/tests/data/test2047 b/tests/data/test2047 -index 76bed3cc9..1d7be6db3 100644 ---- a/tests/data/test2047 -+++ b/tests/data/test2047 -@@ -39,16 +39,14 @@ OK - http - - --idn -+IDN - proxy -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - Connection reuse with IDN host name over HTTP proxy - -diff --git a/tests/data/test2048 b/tests/data/test2048 -index f14c8fbe8..63da9c761 100644 ---- a/tests/data/test2048 -+++ b/tests/data/test2048 -@@ -26,7 +26,7 @@ https Server-localhost-sv.pem - pinnedpubkey no-match must fail even when insecure - - ----insecure --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost.nn-sv.pub.der https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --insecure --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost.nn-sv.pub.der https://localhost:%HTTPSPORT/%TESTNUMBER - - - -diff --git a/tests/data/test205 b/tests/data/test205 -index 8239f6322..d3fbce76b 100644 ---- a/tests/data/test205 -+++ b/tests/data/test205 -@@ -14,10 +14,10 @@ FAILURE - file - - --"upload" with file:// -+"upload" nonexisting with file:// - - --file://localhost/%PWD/%LOGDIR/nonexisting/result%TESTNUMBER.txt -T %LOGDIR/upload%TESTNUMBER.txt -+file://localhost/%FILE_PWD/%LOGDIR/nonexisting/result%TESTNUMBER.txt -T %LOGDIR/upload%TESTNUMBER.txt - - - data -diff --git a/tests/data/test2056 b/tests/data/test2056 -index 008f137df..80e592025 100644 ---- a/tests/data/test2056 -+++ b/tests/data/test2056 -@@ -40,7 +40,7 @@ HTTP Negotiate authentication (stub krb5) - - GSS-API - ld_preload --!debug -+!Debug - - - LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so -diff --git a/tests/data/test2057 b/tests/data/test2057 -index dfc7798f6..5cbb94590 100644 ---- a/tests/data/test2057 -+++ b/tests/data/test2057 -@@ -51,12 +51,12 @@ Nice auth sir! - http - - --HTTP Negotiate authentication (stub ntlm) -+HTTP Negotiate authentication (stub NTLM) - - - GSS-API - ld_preload --!debug -+!Debug - - - LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so -diff --git a/tests/data/test2070 b/tests/data/test2070 -index 38b6ca89d..e46f4588f 100644 ---- a/tests/data/test2070 -+++ b/tests/data/test2070 -@@ -26,6 +26,7 @@ MooMoo - - SSL - Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -34,16 +35,12 @@ https Server-localhost-sv.pem - Ignore certificate revocation "best effort" strategy - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2072 b/tests/data/test2072 -index 50cb4b60a..c1a252094 100644 ---- a/tests/data/test2072 -+++ b/tests/data/test2072 -@@ -21,13 +21,13 @@ moo - file - - --file:// with unix path resolution behavior for the case of extra slashes -+file:// with Unix path resolution behavior for the case of extra slashes - - --file:////%PWD/%LOGDIR/test%TESTNUMBER.txt -+file:////%FILE_PWD/%LOGDIR/test%TESTNUMBER.txt - - --perl -e "print 'Test requires a unix system' if ( $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'dos' || $^O eq 'msys');" -+%PERL -e "print 'Test requires a Unix system' if ( $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'dos' || $^O eq 'msys');" - - - foo -diff --git a/tests/data/test2079 b/tests/data/test2079 -index 0164d1b3b..09e36be2b 100644 ---- a/tests/data/test2079 -+++ b/tests/data/test2079 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,16 +36,12 @@ https Server-localhost-sv.pem - simple HTTPS GET with PEM public key pinning (Schannel variant) - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.pem --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey %SRCDIR/certs/Server-localhost-sv.pub.pem --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test2087 b/tests/data/test2087 -index eb8d3bad8..5b7cce5d4 100644 ---- a/tests/data/test2087 -+++ b/tests/data/test2087 -@@ -27,6 +27,7 @@ MooMoo - SSL - SSLpinning - Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -35,16 +36,12 @@ https Server-localhost-sv.pem - simple HTTPS GET with base64-sha256 public key pinning (Schannel variant) - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//AAUDLk4c98xcFUDvA9i/MnA9HuO03IPi15r+Cx9OXnc= --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --pinnedpubkey sha256//%sha256b64file[%SRCDIR/certs/Server-localhost-sv.pub.der]sha256b64file% --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test210 b/tests/data/test210 -index 1ee313d76..c4ccb6b2c 100644 ---- a/tests/data/test210 -+++ b/tests/data/test210 -@@ -33,6 +33,9 @@ data blobb - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test2100 b/tests/data/test2100 -index 120a6af7a..3f5f5d923 100644 ---- a/tests/data/test2100 -+++ b/tests/data/test2100 -@@ -47,9 +47,9 @@ http - # requires IPv6 so that we can assume and compare both DoH requests - - --debug -+Debug - DoH --ipv6 -+IPv6 - - - HTTP GET using DoH -diff --git a/tests/data/test211 b/tests/data/test211 -index 6830727ab..01dcad0ee 100644 ---- a/tests/data/test211 -+++ b/tests/data/test211 -@@ -34,6 +34,9 @@ data blobb - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test212 b/tests/data/test212 -index db0201e15..a16bf4211 100644 ---- a/tests/data/test212 -+++ b/tests/data/test212 -@@ -23,7 +23,7 @@ ftp - - # EPRT is only sent when IPv6 is enabled - --ipv6 -+IPv6 - - - Get two FTP files with no remote EPRT support -@@ -39,6 +39,9 @@ data blobb - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip the addresses and port number but leave the rest - - s/^(EPRT \|1\|)\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\|\d{1,5}\|/$1/ -diff --git a/tests/data/test215 b/tests/data/test215 -index cead9c742..d2ba2c702 100644 ---- a/tests/data/test215 -+++ b/tests/data/test215 -@@ -7,9 +7,7 @@ FTP - - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -21,7 +19,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - -@@ -40,6 +38,9 @@ ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER/ ftp://%HOSTIP:%FTPPORT/a/path/%TESTNU - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test216 b/tests/data/test216 -index 1be87c0d1..a0ec72be1 100644 ---- a/tests/data/test216 -+++ b/tests/data/test216 -@@ -27,6 +27,9 @@ upload this file twice - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test227 b/tests/data/test227 -index f7b445185..bf55fdd6c 100644 ---- a/tests/data/test227 -+++ b/tests/data/test227 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -Q "NOOP 1" -Q "+NOOP 2" -Q "-NOOP 3" -Q "*FA - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test228 b/tests/data/test228 -index 8e7d73ff0..ae19b534b 100644 ---- a/tests/data/test228 -+++ b/tests/data/test228 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --ftp-account "one count" - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test2300 b/tests/data/test2300 -index fa620a1b1..e8a145929 100644 ---- a/tests/data/test2300 -+++ b/tests/data/test2300 -@@ -27,7 +27,7 @@ upgrade - - # for the forced CURL_ENTROPY - --debug -+Debug - ws - - -diff --git a/tests/data/test2301 b/tests/data/test2301 -index 1f8ed662b..cc728d89a 100644 ---- a/tests/data/test2301 -+++ b/tests/data/test2301 -@@ -29,7 +29,7 @@ upgrade - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - - -diff --git a/tests/data/test2302 b/tests/data/test2302 -index 013c324e8..9ade6a1e5 100644 ---- a/tests/data/test2302 -+++ b/tests/data/test2302 -@@ -29,7 +29,7 @@ upgrade - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - - -diff --git a/tests/data/test2303 b/tests/data/test2303 -index dbd1115c8..79cb4c2ad 100644 ---- a/tests/data/test2303 -+++ b/tests/data/test2303 -@@ -22,7 +22,7 @@ hello - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - - -diff --git a/tests/data/test2304 b/tests/data/test2304 -index 895518fb4..8ade3e771 100644 ---- a/tests/data/test2304 -+++ b/tests/data/test2304 -@@ -29,7 +29,7 @@ upgrade - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - - -diff --git a/tests/data/test2305 b/tests/data/test2305 -index 869f6d36b..773b5df3a 100644 ---- a/tests/data/test2305 -+++ b/tests/data/test2305 -@@ -31,7 +31,7 @@ upgrade - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - - -@@ -50,7 +50,7 @@ ws://%HOSTIP:%HTTPPORT/%TESTNUMBER %LOGDIR/save%TESTNUMBER - - # - -- -+ - %repeat[256 x helothisisdaniel]% - %repeat[256 x helothisisdaniel]% - %repeat[256 x helothisisdaniel]% -diff --git a/tests/data/test2307 b/tests/data/test2307 -index ce260ac1c..7c9f625b0 100644 ---- a/tests/data/test2307 -+++ b/tests/data/test2307 -@@ -29,7 +29,7 @@ upgrade - - # require debug for the forced CURL_ENTROPY - --debug -+Debug - ws - !hyper - -diff --git a/tests/data/test2308 b/tests/data/test2308 -new file mode 100644 -index 000000000..3881d353d ---- /dev/null -+++ b/tests/data/test2308 -@@ -0,0 +1,57 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+# -+# This reproduces the #13669 issue -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# Client-side -+ -+ -+http -+ -+# tool to run -+ -+lib%TESTNUMBER -+ -+ -+ -+verify return code when write callback returns error -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+Accept: */* -+ -+ -+ -+Returned 23, should be 23. -+ -+ -+ -diff --git a/tests/data/test235 b/tests/data/test235 -index 4bfe7497e..485be98ec 100644 ---- a/tests/data/test235 -+++ b/tests/data/test235 -@@ -32,6 +32,9 @@ worx? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test236 b/tests/data/test236 -index a66fa046d..13493f26a 100644 ---- a/tests/data/test236 -+++ b/tests/data/test236 -@@ -33,6 +33,9 @@ Test data - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - - USER anonymous -diff --git a/tests/data/test238 b/tests/data/test238 -index 3c0db0441..71b46ddc3 100644 ---- a/tests/data/test238 -+++ b/tests/data/test238 -@@ -27,6 +27,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # 13 = CURLE_FTP_WEIRD_PASV_REPLY - - 13 -diff --git a/tests/data/test240 b/tests/data/test240 -index d033ae35c..75bd4bb3d 100644 ---- a/tests/data/test240 -+++ b/tests/data/test240 -@@ -29,7 +29,7 @@ Funny-head: yesyes - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test2400 b/tests/data/test2400 -index e920f4f16..ef7b12669 100644 ---- a/tests/data/test2400 -+++ b/tests/data/test2400 -@@ -27,8 +27,8 @@ Funny-head: yesyes - # Client-side - - --debug --h2c -+Debug -+http/2 - SSL - - -@@ -36,7 +36,7 @@ http - http/2 - - --HTTP/2 GET -+HTTP/2 GET over HTTPS - - - -diff --git a/tests/data/test2401 b/tests/data/test2401 -index ef5fbb181..9929c1394 100644 ---- a/tests/data/test2401 -+++ b/tests/data/test2401 -@@ -25,16 +25,15 @@ Funny-head: yesyes - # Client-side - - --debug --h2c -+Debug -+http/2 - SSL - - --http - http/2 - - --HTTP/2 GET -+HTTP/2 POST over HTTPS - - - -@@ -57,7 +56,7 @@ via: 1.1 nghttpx - - - --POST /2401 HTTP/1.1 -+POST /%TESTNUMBER HTTP/1.1 - Host: %HOSTIP:%HTTP2TLSPORT - User-Agent: curl/%VERSION - Accept: */* -diff --git a/tests/data/test2402 b/tests/data/test2402 -index 44d48f85f..48a485624 100644 ---- a/tests/data/test2402 -+++ b/tests/data/test2402 -@@ -47,18 +47,17 @@ file contents should appear once for each file - # Client-side - - --h2c -+http/2 - SSL - - --http - http/2 - - - lib%TESTNUMBER - - --HTTP GET multiple over HTTP/2 -+HTTP GET multiple files over HTTP/2 using HTTPS - - - https://%HOSTIP:%HTTP2TLSPORT/path/%TESTNUMBER %HOSTIP %HTTP2TLSPORT -diff --git a/tests/data/test2403 b/tests/data/test2403 -index 7a993d731..222f236d7 100644 ---- a/tests/data/test2403 -+++ b/tests/data/test2403 -@@ -29,16 +29,15 @@ Funny-head: yesyes - # Client-side - - --h2c -+http/2 - SSL - headers-api - - --http - http/2 - - --HTTP/2 GET -+HTTP/2 GET using %{header_json} - - - -diff --git a/tests/data/test2404 b/tests/data/test2404 -index bcf1035aa..89461a468 100644 ---- a/tests/data/test2404 -+++ b/tests/data/test2404 -@@ -47,11 +47,10 @@ file contents should appear once for each file - # Client-side - - --h2c -+http/2 - SSL - - --http - http/2 - - -diff --git a/tests/data/test2405 b/tests/data/test2405 -new file mode 100644 -index 000000000..8489156e7 ---- /dev/null -+++ b/tests/data/test2405 -@@ -0,0 +1,50 @@ -+ -+ -+ -+multi -+HTTP -+HTTP/2 -+ -+ -+ -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6007 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+%repeat[1000 x foobar]% -+ -+ -+ -+# Client-side -+ -+ -+http/2 -+ -+ -+lib%TESTNUMBER -+ -+ -+checking curl_multi_waitfds functionality -+ -+ -+http://%HOSTIP:%HTTP2PORT/%TESTNUMBER -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+ -+ -+ -diff --git a/tests/data/test2406 b/tests/data/test2406 -new file mode 100644 -index 000000000..6bf4fa8cd ---- /dev/null -+++ b/tests/data/test2406 -@@ -0,0 +1,65 @@ -+ -+ -+ -+HTTP -+HTTP GET -+HTTP/2 -+HTTPS -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 404 nope -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+Debug -+http/2 -+SSL -+ -+ -+http/2 -+ -+ -+HTTP/2 over HTTPS with -f -+ -+ -+ -+ -+-k --http2 -f "https://%HOSTIP:%HTTP2TLSPORT/%TESTNUMBER" -+ -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+HTTP/2 404 -+date: Tue, 09 Nov 2010 14:49:00 GMT -+content-length: 6 -+content-type: text/html -+funny-head: yesyes -+server: nghttpx -+via: 1.1 nghttpx -+ -+ -+ -+22 -+ -+ -+ -diff --git a/tests/data/test241 b/tests/data/test241 -index 92a431420..38dea3fd5 100644 ---- a/tests/data/test241 -+++ b/tests/data/test241 -@@ -24,7 +24,7 @@ hello - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test242 b/tests/data/test242 -index a498ab29b..91aeb381d 100644 ---- a/tests/data/test242 -+++ b/tests/data/test242 -@@ -24,7 +24,7 @@ hello - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test244 b/tests/data/test244 -index 782be2be4..ad9cf4fe2 100644 ---- a/tests/data/test244 -+++ b/tests/data/test244 -@@ -41,6 +41,9 @@ FTP dir listing with nocwd and URL encoded path - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test247 b/tests/data/test247 -index 40f42e7d0..5eade37b3 100644 ---- a/tests/data/test247 -+++ b/tests/data/test247 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt -z "apr 1 2005 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - - -diff --git a/tests/data/test248 b/tests/data/test248 -index 097e1e583..2d5c845ba 100644 ---- a/tests/data/test248 -+++ b/tests/data/test248 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt -z "apr 1 2005 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - data - to -diff --git a/tests/data/test250 b/tests/data/test250 -index 455d9ea1a..59f7fa311 100644 ---- a/tests/data/test250 -+++ b/tests/data/test250 -@@ -11,7 +11,7 @@ SLOWDOWN - - # When doing LIST, we get the default list output hard-coded in the test - # FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - SLOWDOWN - -@@ -46,6 +46,9 @@ ftp://%HOSTIP:%FTPPORT/ - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test2500 b/tests/data/test2500 -index 6ec739d1a..f880672da 100644 ---- a/tests/data/test2500 -+++ b/tests/data/test2500 -@@ -33,7 +33,6 @@ http/3 - nghttpx-h3 - - --http - http/3 - - -diff --git a/tests/data/test2501 b/tests/data/test2501 -index 4db52ecf6..1f35372f1 100644 ---- a/tests/data/test2501 -+++ b/tests/data/test2501 -@@ -25,12 +25,11 @@ Funny-head: yesyes - # Client-side - - --debug -+Debug - http - http/3 - - --http - http/3 - - -diff --git a/tests/data/test2502 b/tests/data/test2502 -index aae65e1cc..2efd04f2d 100644 ---- a/tests/data/test2502 -+++ b/tests/data/test2502 -@@ -50,7 +50,6 @@ file contents should appear once for each file - http/3 - - --http - http/3 - - -@@ -92,10 +91,10 @@ Via: 3 nghttpx - ^Host:.* - - --* Connection #0 to host localhost left intact --* Connection #0 to host localhost left intact --* Connection #0 to host localhost left intact --* Connection #0 to host localhost left intact -+== Info: Connection #0 to host localhost left intact -+== Info: Connection #0 to host localhost left intact -+== Info: Connection #0 to host localhost left intact -+== Info: Connection #0 to host localhost left intact - - - $_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/)) -diff --git a/tests/data/test2503 b/tests/data/test2503 -index 9877ee4c1..ab86c66be 100644 ---- a/tests/data/test2503 -+++ b/tests/data/test2503 -@@ -33,7 +33,6 @@ nghttpx-h3 - headers-api - - --http - http/3 - - -diff --git a/tests/data/test251 b/tests/data/test251 -index 46124bfec..6de2003c8 100644 ---- a/tests/data/test251 -+++ b/tests/data/test251 -@@ -8,9 +8,7 @@ SLOWDOWN - - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -22,7 +20,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - SLOWDOWN - -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT/ -P %CLIENTIP - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test252 b/tests/data/test252 -index 220cda189..35c3014a0 100644 ---- a/tests/data/test252 -+++ b/tests/data/test252 -@@ -10,9 +10,7 @@ EPSV - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,14 +22,14 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -47,6 +45,9 @@ FTP IPv6 dir list PASV - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test253 b/tests/data/test253 -index 2c1008d7e..8f7192d21 100644 ---- a/tests/data/test253 -+++ b/tests/data/test253 -@@ -10,9 +10,7 @@ EPRT - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -21,17 +19,17 @@ drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT - lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin - dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev - drwxrwxrwx 2 98 98 512 May 29 16:04 download.html --dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc -+dr-xr-xr-x 2 0 1 512 Nov 30 1995 moo - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -47,6 +45,9 @@ FTP IPv6 dir list with EPRT - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^(EPRT \|2\|::1\|)(.*)/$1/ - -diff --git a/tests/data/test254 b/tests/data/test254 -index 30978758f..ede445355 100644 ---- a/tests/data/test254 -+++ b/tests/data/test254 -@@ -11,9 +11,7 @@ EPSV - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,14 +23,14 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -48,6 +46,9 @@ FTP IPv6 dir list PASV and --disable-epsv - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test255 b/tests/data/test255 -index 37b9da2ac..190908e35 100644 ---- a/tests/data/test255 -+++ b/tests/data/test255 -@@ -11,9 +11,7 @@ EPRT - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,14 +23,14 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # - # Client-side - - --ipv6 -+IPv6 - - - ftp-ipv6 -@@ -48,6 +46,9 @@ FTP IPv6 dir list with EPRT and --disable-eprt - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^(EPRT \|2\|::1\|)(.*)/$1/ - -diff --git a/tests/data/test2600 b/tests/data/test2600 -index 5b88aedb7..0b4ee8b2f 100644 ---- a/tests/data/test2600 -+++ b/tests/data/test2600 -@@ -15,8 +15,9 @@ none - - - unittest --debug -+Debug - http -+!win32 - - - connection filter connect/destroy unit tests -diff --git a/tests/data/test2604 b/tests/data/test2604 -new file mode 100644 -index 000000000..4e825aa27 ---- /dev/null -+++ b/tests/data/test2604 -@@ -0,0 +1,22 @@ -+ -+ -+ -+unittest -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+unittest -+sftp -+ -+ -+Curl_get_pathname unit test -+ -+ -+ -diff --git a/tests/data/test261 b/tests/data/test261 -index d5f940372..192b2bcd7 100644 ---- a/tests/data/test261 -+++ b/tests/data/test261 -@@ -34,6 +34,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test263 b/tests/data/test263 -index 93e98a197..648702529 100644 ---- a/tests/data/test263 -+++ b/tests/data/test263 -@@ -24,7 +24,7 @@ hello - # Client-side - - --ipv6 -+IPv6 - proxy - - -diff --git a/tests/data/test268 b/tests/data/test268 -index 3a1ab6a9b..0d205fe73 100644 ---- a/tests/data/test268 -+++ b/tests/data/test268 -@@ -32,7 +32,7 @@ Funny-head: yesyes - http - - --JSON encoding of unicode string -+JSON encoding of Unicode string - - - %hex[%e2%80%9c]hex% -diff --git a/tests/data/test270 b/tests/data/test270 -index efa183f15..f4f5a0231 100644 ---- a/tests/data/test270 -+++ b/tests/data/test270 -@@ -36,6 +36,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --ftp-skip-pasv-ip --disable-epsv - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test272 b/tests/data/test272 -index 2857c3eac..5607a1081 100644 ---- a/tests/data/test272 -+++ b/tests/data/test272 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -z "2004 jan 1 12:12:12 UTC" - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test280 b/tests/data/test280 -index 1ed41e652..dbe809e1d 100644 ---- a/tests/data/test280 -+++ b/tests/data/test280 -@@ -10,9 +10,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,8 +21,8 @@ dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev - drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub --dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+dr-xr-xr-x 5 0 1 512 Oct 1 1997 fine -+ - - REPLY USER 530 We don't like USER commands - COUNT USER 1 -@@ -48,6 +46,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER/ --ftp-alternative-to-user "USER replacement" - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - USER replacement -diff --git a/tests/data/test29 b/tests/data/test29 -index 64d5e6c6b..689ac43ee 100644 ---- a/tests/data/test29 -+++ b/tests/data/test29 -@@ -26,6 +26,9 @@ wait 10 - - http - -+ -+http -+ - - HTTP with 2 secs timeout - -diff --git a/tests/data/test290 b/tests/data/test290 -index e7048a538..6ffa9a726 100644 ---- a/tests/data/test290 -+++ b/tests/data/test290 -@@ -27,6 +27,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --max-filesize 30 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 63 - -diff --git a/tests/data/test291 b/tests/data/test291 -index 05cc2b444..2385f7db4 100644 ---- a/tests/data/test291 -+++ b/tests/data/test291 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --max-filesize 100 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test294 b/tests/data/test294 -index b840b8c70..4e2e9857d 100644 ---- a/tests/data/test294 -+++ b/tests/data/test294 -@@ -11,9 +11,7 @@ ACCT - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - REPLY PASS 332 Give me an ACCT now - REPLY ACCT 230 Thank-you for the ACCT -@@ -49,6 +47,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER/ --ftp-account "data for acct" - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test296 b/tests/data/test296 -index c88ec99bf..d4b87dfa4 100644 ---- a/tests/data/test296 -+++ b/tests/data/test296 -@@ -31,6 +31,9 @@ FTP CWD with --ftp-method multicwd - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test297 b/tests/data/test297 -index 99c10d3e1..d982a3b7f 100644 ---- a/tests/data/test297 -+++ b/tests/data/test297 -@@ -31,6 +31,9 @@ FTP CWD with --ftp-method singlecwd - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test298 b/tests/data/test298 -index 5188c8547..3880a6073 100644 ---- a/tests/data/test298 -+++ b/tests/data/test298 -@@ -31,6 +31,9 @@ FTP CWD with --ftp-method nocwd - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test3000 b/tests/data/test3000 -index 05f4a010e..43c2695c9 100644 ---- a/tests/data/test3000 -+++ b/tests/data/test3000 -@@ -26,6 +26,7 @@ MooMoo - - SSL - !Schannel -+local-http - - - https Server-localhost-firstSAN-sv.pem -@@ -34,12 +35,8 @@ https Server-localhost-firstSAN-sv.pem - HTTPS GET to localhost, first subject alt name matches, CN does not match - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3001 b/tests/data/test3001 -index 3a954324b..9bfeb708a 100644 ---- a/tests/data/test3001 -+++ b/tests/data/test3001 -@@ -26,6 +26,7 @@ MooMoo - - SSL - !Schannel -+local-http - - - https Server-localhost-lastSAN-sv.pem -@@ -34,12 +35,8 @@ https Server-localhost-lastSAN-sv.pem - HTTPS GET to localhost, last subject alt name matches, CN does not match - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3015 b/tests/data/test3015 -index 5b59bba32..41e0640bc 100644 ---- a/tests/data/test3015 -+++ b/tests/data/test3015 -@@ -50,7 +50,7 @@ http - HTTP GET -w num_headers with redirected fetch (2 connects) - - --http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w "%{num_headers}\n" -L -o/dev/null -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w "%{num_headers}\n" -L -o%DEV_NULL - - - -diff --git a/tests/data/test3016 b/tests/data/test3016 -index d04633c7a..e1285a325 100644 ---- a/tests/data/test3016 -+++ b/tests/data/test3016 -@@ -21,7 +21,7 @@ GET a directory using file:// - !win32 - - --file://%PWD/ -+file://%FILE_PWD/ - - - -diff --git a/tests/data/test3017 b/tests/data/test3017 -index 4d907b39f..209babf20 100644 ---- a/tests/data/test3017 -+++ b/tests/data/test3017 -@@ -47,7 +47,7 @@ mqtt://%HOSTIP:%MQTTPORT/%TESTNUMBER -m 3 - - s/^(.* 00044d5154540402003c000c6375726c).*/$1/ - --# on windows the disconnect is never seen - no idea why -+# on Windows the disconnect is never seen - no idea why - - ^server DISCONNECT 0 e000 - -diff --git a/tests/data/test3018 b/tests/data/test3018 -index 71e06b593..d58daf41a 100644 ---- a/tests/data/test3018 -+++ b/tests/data/test3018 -@@ -45,7 +45,7 @@ mqtt://%HOSTIP:%MQTTPORT/%TESTNUMBER --max-filesize 11 - - s/^(.* 00044d5154540402003c000c6375726c).*/$1/ - --# on windows the disconnect is never seen - no idea why -+# on Windows the disconnect is never seen - no idea why - - ^server DISCONNECT 0 e000 - -diff --git a/tests/data/test3021 b/tests/data/test3021 -index bdf8f375c..56b4f9b4f 100644 ---- a/tests/data/test3021 -+++ b/tests/data/test3021 -@@ -46,8 +46,5 @@ test - - 0 - -- --disable -- - - -diff --git a/tests/data/test3022 b/tests/data/test3022 -index d76e5f493..1213a0288 100644 ---- a/tests/data/test3022 -+++ b/tests/data/test3022 -@@ -46,8 +46,5 @@ test - - 0 - -- --disable -- - - -diff --git a/tests/data/test3023 b/tests/data/test3023 -index fe43c199f..09e66331d 100644 ---- a/tests/data/test3023 -+++ b/tests/data/test3023 -@@ -26,6 +26,7 @@ MooMoo - - SSL - Schannel -+local-http - - - https Server-localhost-firstSAN-sv.pem -@@ -34,16 +35,12 @@ https Server-localhost-firstSAN-sv.pem - HTTPS GET to localhost, first subject alt name matches, CN does not match (Schannel variant) - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3024 b/tests/data/test3024 -index 55b26788e..11c7643ff 100644 ---- a/tests/data/test3024 -+++ b/tests/data/test3024 -@@ -26,6 +26,7 @@ MooMoo - - SSL - Schannel -+local-http - - - https Server-localhost-lastSAN-sv.pem -@@ -34,16 +35,12 @@ https Server-localhost-lastSAN-sv.pem - HTTPS GET to localhost, last subject alt name matches, CN does not match (Schannel variant) - - --# This test is pointless if we're not using the schannel backend -+# This test is pointless if we are not using the Schannel backend - CURL_SSL_BACKEND=schannel - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --ssl-revoke-best-effort https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3027 b/tests/data/test3027 -index 05a811f4e..416c0079d 100644 ---- a/tests/data/test3027 -+++ b/tests/data/test3027 -@@ -40,6 +40,9 @@ data blobb - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test3029 b/tests/data/test3029 -index 2e51bbeaf..143660209 100644 ---- a/tests/data/test3029 -+++ b/tests/data/test3029 -@@ -36,4 +36,4 @@ Content-Length: 6 - - - -- -\ No newline at end of file -+ -diff --git a/tests/data/test3030 b/tests/data/test3030 -index 7e169cf43..56da81c7c 100644 ---- a/tests/data/test3030 -+++ b/tests/data/test3030 -@@ -40,4 +40,4 @@ Content-Length: 6 - - - -- -\ No newline at end of file -+ -diff --git a/tests/data/test3031 b/tests/data/test3031 -new file mode 100644 -index 000000000..58edc376d ---- /dev/null -+++ b/tests/data/test3031 -@@ -0,0 +1,67 @@ -+ -+ -+ -+--dump-header -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+http -+ -+ -+--output-dir with --create-dirs -+ -+ -+http://%HOSTIP:%HTTPPORT/this/is/the/%TESTNUMBER --dump-header %PWD/%LOGDIR/tmp/out.txt --create-dirs -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /this/is/the/%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+ -+ -+ -diff --git a/tests/data/test307 b/tests/data/test307 -index ce3232ac7..475fdaee3 100644 ---- a/tests/data/test307 -+++ b/tests/data/test307 -@@ -29,7 +29,7 @@ OpenSSL - https - - --perl %SRCDIR/libtest/test%TESTNUMBER.pl %CURL -+%PERL %SRCDIR/libtest/test%TESTNUMBER.pl %CURL - - - -diff --git a/tests/data/test31 b/tests/data/test31 -index 3ceaad0f9..d9d073996 100644 ---- a/tests/data/test31 -+++ b/tests/data/test31 -@@ -144,11 +144,9 @@ TZ=GMT - - http://test31.curl:%HTTPPORT/we/want/%TESTNUMBER -b none -c %LOGDIR/jar%TESTNUMBER.txt --resolve test31.curl:%HTTPPORT:127.0.0.1 - -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - cookies -+local-http - - - -diff --git a/tests/data/test310 b/tests/data/test310 -index b9f1850ea..1baf32095 100644 ---- a/tests/data/test310 -+++ b/tests/data/test310 -@@ -26,6 +26,7 @@ MooMoo - - SSL - !Schannel -+local-http - - - https Server-localhost-sv.pem -@@ -34,12 +35,8 @@ https Server-localhost-sv.pem - simple HTTPS GET - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3102 b/tests/data/test3102 -index 4df7ba9c1..7635e6543 100644 ---- a/tests/data/test3102 -+++ b/tests/data/test3102 -@@ -20,7 +20,6 @@ HTTP GET - - SSL - !bearssl --!mbedtls - !rustls - !wolfssl - -diff --git a/tests/data/test311 b/tests/data/test311 -index a3f9ed0e2..61fe2e90c 100644 ---- a/tests/data/test311 -+++ b/tests/data/test311 -@@ -17,6 +17,7 @@ PEM certificate - - - SSL -+local-http - - - https Server-localhost0h-sv.pem -@@ -25,12 +26,8 @@ https Server-localhost0h-sv.pem - HTTPS wrong subjectAltName but right CN - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test312 b/tests/data/test312 -index c8c46b821..52fc37cbd 100644 ---- a/tests/data/test312 -+++ b/tests/data/test312 -@@ -17,6 +17,7 @@ PEM certificate - - - SSL -+local-http - - - https Server-localhost.nn-sv.pem -@@ -25,12 +26,8 @@ https Server-localhost.nn-sv.pem - HTTPS GET to localhost and null-prefixed CN cert - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test313 b/tests/data/test313 -index 12f91f965..cff9a9b25 100644 ---- a/tests/data/test313 -+++ b/tests/data/test313 -@@ -13,6 +13,7 @@ CRL - - - SSL -+local-http - - - https Server-localhost-sv.pem -@@ -21,12 +22,8 @@ https Server-localhost-sv.pem - CRL test - - ----cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --crlfile %SRCDIR/certs/Server-localhost-sv.crl https://localhost:%HTTPSPORT/%TESTNUMBER -+-4 --cacert %SRCDIR/certs/EdelCurlRoot-ca.crt --crlfile %SRCDIR/certs/Server-localhost-sv.crl https://localhost:%HTTPSPORT/%TESTNUMBER - --# Ensure that we're running on localhost because we're checking the host name -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test3202 b/tests/data/test3202 -index 25ec6073b..48a74e132 100644 ---- a/tests/data/test3202 -+++ b/tests/data/test3202 -@@ -31,7 +31,7 @@ These data aren't actually sent to the client - # Client-side - - --ipv6 -+IPv6 - - - http-ipv6 -diff --git a/tests/data/test3203 b/tests/data/test3203 -new file mode 100644 -index 000000000..527e870a4 ---- /dev/null -+++ b/tests/data/test3203 -@@ -0,0 +1,41 @@ -+ -+ -+ -+HTTP -+HTTP GET -+FILE -+ -+ -+ -+# -+# Client-side -+ -+ -+file -+ -+ -+GET a directory using file:// -+ -+ -+ -+!win32 -+ -+ -+file://localhost%FILE_PWD/%LOGDIR/test%TESTNUMBER.dir/ -+ -+ -+Contents of file are irrelevant -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+0 -+ -+ -+dir-listing-test.txt -+ -+ -+ -diff --git a/tests/data/test3204 b/tests/data/test3204 -new file mode 100644 -index 000000000..8cc9c2f5b ---- /dev/null -+++ b/tests/data/test3204 -@@ -0,0 +1,52 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 304 Not Modified -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+ETag: "21025-dc7-39462498" -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+Use --etag-compare and --etag-save on an existing file -+ -+ -+"21025-dc7-39462498" -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --etag-compare %LOGDIR/etag%TESTNUMBER --etag-save %LOGDIR/etag%TESTNUMBER -+ -+ -+ -+# Verify that the file still exists with the correct etag value. -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+If-None-Match: "21025-dc7-39462498" -+ -+ -+ -+"21025-dc7-39462498" -+ -+ -+ -diff --git a/tests/data/test3205 b/tests/data/test3205 -new file mode 100644 -index 000000000..3a26cd6d8 ---- /dev/null -+++ b/tests/data/test3205 -@@ -0,0 +1,22 @@ -+ -+ -+ -+unittest -+cipher_suite -+ -+ -+ -+# -+# Client-side -+ -+ -+none -+ -+ -+unittest -+ -+ -+cipher suite name lookup -+ -+ -+ -diff --git a/tests/data/test3207 b/tests/data/test3207 -new file mode 100644 -index 000000000..01b3353a3 ---- /dev/null -+++ b/tests/data/test3207 -@@ -0,0 +1,175 @@ -+ -+ -+ -+HTTPS -+ -+ -+ -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Type: text/html -+Content-Length: 29 -+ -+run 1: foobar and so on fun! -+ -+ -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+run 1: foobar and so on fun! -+ -+ -+ -+# Client-side -+ -+ -+SSL -+OpenSSL -+ -+ -+https -+ -+ -+concurrent HTTPS GET using shared ssl session cache -+ -+ -+lib%TESTNUMBER -+ -+# provide URL and ca-cert -+ -+https://localhost:%HTTPSPORT/%TESTNUMBER %SRCDIR/certs/EdelCurlRoot-ca.crt -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+ -diff --git a/tests/data/test336 b/tests/data/test336 -index f50b42adb..4e881379a 100644 ---- a/tests/data/test336 -+++ b/tests/data/test336 -@@ -41,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --range 3-6 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test337 b/tests/data/test337 -index d44a712fb..b82f94786 100644 ---- a/tests/data/test337 -+++ b/tests/data/test337 -@@ -41,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --range 3-6 - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test348 b/tests/data/test348 -index 55e9d608d..988e5bd04 100644 ---- a/tests/data/test348 -+++ b/tests/data/test348 -@@ -36,6 +36,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - data - to -diff --git a/tests/data/test350 b/tests/data/test350 -index 6830d704d..7342275d4 100644 ---- a/tests/data/test350 -+++ b/tests/data/test350 -@@ -9,9 +9,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +21,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT// --ftp-method multicwd - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test351 b/tests/data/test351 -index ef21364ad..31c07fa3c 100644 ---- a/tests/data/test351 -+++ b/tests/data/test351 -@@ -9,9 +9,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +21,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT// --ftp-method nocwd - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test352 b/tests/data/test352 -index cfcdc1f10..d54ab60eb 100644 ---- a/tests/data/test352 -+++ b/tests/data/test352 -@@ -9,9 +9,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +21,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT// --ftp-method singlecwd - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test353 b/tests/data/test353 -index 26115d675..dedd06960 100644 ---- a/tests/data/test353 -+++ b/tests/data/test353 -@@ -9,9 +9,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +21,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -43,6 +41,9 @@ ftp://%HOSTIP:%FTPPORT/ --ftp-method singlecwd - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test354 b/tests/data/test354 -index dc6d732d8..9a40d49c6 100644 ---- a/tests/data/test354 -+++ b/tests/data/test354 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PWD -diff --git a/tests/data/test356 b/tests/data/test356 -index 3fb001c58..1d441d7e7 100644 ---- a/tests/data/test356 -+++ b/tests/data/test356 -@@ -29,7 +29,7 @@ Alt-Svc: h1="nowhere.foo:70000" - # Client-side - - --debug -+Debug - alt-svc - - -diff --git a/tests/data/test358 b/tests/data/test358 -index 5df596de0..9db8b66f1 100644 ---- a/tests/data/test358 -+++ b/tests/data/test358 -@@ -29,7 +29,7 @@ Alt-Svc: h2=":%HTTP2PORT", ma=315360000; persist=0 - - - alt-svc --debug -+Debug - h2c - - -diff --git a/tests/data/test359 b/tests/data/test359 -index 117b4defe..2b7e52ce8 100644 ---- a/tests/data/test359 -+++ b/tests/data/test359 -@@ -29,7 +29,7 @@ Alt-Svc: h2=":%HTTP2PORT", ma=315360000; persist=0 - - - alt-svc --debug -+Debug - h2c - - -diff --git a/tests/data/test362 b/tests/data/test362 -index e8ce9731e..d259593fd 100644 ---- a/tests/data/test362 -+++ b/tests/data/test362 -@@ -29,6 +29,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T %LOGDIR/test%TESTNUMBER.txt --continue-at - - - -+ -+QUIT -+ - - data - to -diff --git a/tests/data/test363 b/tests/data/test363 -index 7cc7dad99..d2d9661f7 100644 ---- a/tests/data/test363 -+++ b/tests/data/test363 -@@ -43,7 +43,7 @@ contents - # Client-side - - --debug -+Debug - proxy - - -diff --git a/tests/data/test380 b/tests/data/test380 -index bd0c69765..47676e3dd 100644 ---- a/tests/data/test380 -+++ b/tests/data/test380 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -50,6 +48,9 @@ machine %HOSTIP login mary password yram - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER mary - PASS yram -diff --git a/tests/data/test381 b/tests/data/test381 -index 902cc91d1..bf2877302 100644 ---- a/tests/data/test381 -+++ b/tests/data/test381 -@@ -10,9 +10,7 @@ netrc - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -54,6 +52,9 @@ machine %HOSTIP login mary password yram - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER mary - PASS drfrank -diff --git a/tests/data/test389 b/tests/data/test389 -index fcb29f5b8..a38d70eef 100644 ---- a/tests/data/test389 -+++ b/tests/data/test389 -@@ -31,16 +31,16 @@ Funny-head: yesyes - - http - -+ -+local-http -+ - - *.localhost is a local host - - --http://curlmachine.localhost:%HTTPPORT/%TESTNUMBER -+-4 http://curlmachine.localhost:%HTTPPORT/%TESTNUMBER - - # Ensure that we're running on localhost -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - - # -diff --git a/tests/data/test392 b/tests/data/test392 -index 5c1076c82..a9f756d94 100644 ---- a/tests/data/test392 -+++ b/tests/data/test392 -@@ -35,13 +35,11 @@ HTTP secure cookies over localhost - TZ=GMT - - --http://localhost:%HTTPPORT/%TESTNUMBER -b none http://localhost:%HTTPPORT/%TESTNUMBER -+-4 http://localhost:%HTTPPORT/%TESTNUMBER -b none http://localhost:%HTTPPORT/%TESTNUMBER - -- --perl -e "print 'Test requires default test server host' if ( '%HOSTIP' ne '127.0.0.1' );" -- - - cookies -+local-http - - - -diff --git a/tests/data/test400 b/tests/data/test400 -index db774bf12..e20774a4d 100644 ---- a/tests/data/test400 -+++ b/tests/data/test400 -@@ -10,9 +10,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTPS server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -diff --git a/tests/data/test403 b/tests/data/test403 -index 7c2904afb..7c08d5ca8 100644 ---- a/tests/data/test403 -+++ b/tests/data/test403 -@@ -12,9 +12,7 @@ FAILURE - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTPS server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -26,7 +24,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -diff --git a/tests/data/test406 b/tests/data/test406 -index eca49d0d3..db497bf6c 100644 ---- a/tests/data/test406 -+++ b/tests/data/test406 -@@ -10,9 +10,7 @@ LIST - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTPS server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -24,7 +22,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -diff --git a/tests/data/test412 b/tests/data/test412 -index de607baa2..5923054fc 100644 ---- a/tests/data/test412 -+++ b/tests/data/test412 -@@ -28,7 +28,7 @@ Funny-head: yesyes - - - alt-svc --debug -+Debug - - - http -diff --git a/tests/data/test413 b/tests/data/test413 -index 8639306e0..e0aec1eaa 100644 ---- a/tests/data/test413 -+++ b/tests/data/test413 -@@ -28,7 +28,7 @@ Funny-head: yesyes - - - alt-svc --debug -+Debug - - - http -diff --git a/tests/data/test416 b/tests/data/test416 -index b6b10b3df..f50ad70dd 100644 ---- a/tests/data/test416 -+++ b/tests/data/test416 -@@ -38,6 +38,9 @@ FTP growing file support - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test417 b/tests/data/test417 -index 9061f8332..50f4b479b 100644 ---- a/tests/data/test417 -+++ b/tests/data/test417 -@@ -51,31 +51,7 @@ s/^(.*):(.*)[\r\n]*// - - - nomnom -------BEGIN CERTIFICATE----- --MIIERDCCAyygAwIBAgIGDzR1UZ/TMA0GCSqGSIb3DQEBCwUAMGgxCzAJBgNVBAYT --Ak5OMTEwLwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNo --IENsb3VkMSYwJAYDVQQDDB1Ob3J0aGVybiBOb3doZXJlIFRydXN0IEFuY2hvcjAe --Fw0yMjEyMjMxMjIxMzlaFw0zMTAzMTExMjIxMzlaMFQxCzAJBgNVBAYTAk5OMTEw --LwYDVQQKDChFZGVsIEN1cmwgQXJjdGljIElsbHVkaXVtIFJlc2VhcmNoIENsb3Vk --MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK --AoIBAQCrCrAD0Hb+Xs4V3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxa --orWweFGVYoCAcchOn1lZk0ASsqnOss0Xi58n8+PPI3gG0gYjX5sg7EJ3Zq2kXoK0 --TZRy6hNkcvzLgyzXoYv1LkzTwYiyyJgZX++Y/GKAs2fMHyP8XzjNgm4tltk1k/4p --omllwN9Fqz+sFxgAgEq3ybq4Xym7xKwWl8xXNBDJNmVsPtiJRcilQoR8Xs0a6PE+ --VbMhD9A2E/LEL7lzQfqHqtxE1mSW5FpQ+Uqf4KLnafStWs86IOWnCeLP6BmhAK6o --uyICNFyzz7UkTHa/renxuNOGun2TAgMBAAGjggEGMIIBAjAUBgNVHREEDTALggls --b2NhbGhvc3QwCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1Ud --DgQWBBScl7A9s1Cx9tRx4uvLgOqTfJjMcjAfBgNVHSMEGDAWgBSHy7EzLsFnfnHj --5StMTaSzbtJbqTAJBgNVHRMEAjAAMEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcw --AoYnaHR0cDovL3Rlc3QuY3VybC5zZS9jYS9FZGVsQ3VybFJvb3QuY2VyMDgGA1Ud --HwQxMC8wLaAroCmGJ2h0dHA6Ly90ZXN0LmN1cmwuc2UvY2EvRWRlbEN1cmxSb290 --LmNybDANBgkqhkiG9w0BAQsFAAOCAQEAC4rtaof6cRWIJViFG0oJv0MANZN4DXIU --MFHik4Oh2hsvqTGut8dMcsJeMiTxlpNw1T+1hYATdTLPDvhdxKIphEMsdYEmEmqg --y3tXwZJ4hQj6ZFDCe4MCTXkTvGFkTbhr1fGEaxJcaZCtQEfA7d3qimZ+h4UZqonT --PAhyCKFNY2BbmxeeABKhAFLKeAGIGMftW8fk2eu9P6+SUz/+WFcN/PR7e6JP6blc --taRSULRWWkSO2dDt3o9+rBxYdluoecmVq4Ud20wTgkqlQRsp9dOW34DRHgB9ujWU --V4HhCCqBaxwwUDcBGg4mT2vtyVAXNyszP2j+xvAhjOeyeVXyQr0vsA== -------END CERTIFICATE----- -+%strippemfile[%SRCDIR/certs/stunnel-sv.crt]strippemfile% - - - -diff --git a/tests/data/test424 b/tests/data/test424 -index 36ba8c4b7..9ae6b1fab 100644 ---- a/tests/data/test424 -+++ b/tests/data/test424 -@@ -59,10 +59,10 @@ http - # Verify data after the test has been "shot" - - --anotherhost.example+/%TESTNUMBER0002+http+uuuu+pppp+2023+moo.html+ --hello2000+/%TESTNUMBER+h55p+++1+qqqq+ffff -+anotherhost.example+/4240002+http+++2023+moo.html+ -+hello2000+/424+h55p+++1+qqqq+ffff - +++++++ --anotherhost.example+/%TESTNUMBER0002+http+u22u+p22p+2023+moo.html+ -+anotherhost.example+/4240002+http+++2023+moo.html+ - - - -diff --git a/tests/data/test433 b/tests/data/test433 -index e86f3deae..f1c405634 100644 ---- a/tests/data/test433 -+++ b/tests/data/test433 -@@ -20,7 +20,7 @@ Content-Type: text/1 - # - # Client-side - -- -+ - --next - header = "a: a" - data = "curlrc read" -@@ -34,9 +34,9 @@ HOME= - CURL_HOME= - - --Verify XDG_CONFIG_HOME use to find .curlrc -+Verify XDG_CONFIG_HOME use to find curlrc - -- -+ - %HOSTIP:%HTTPPORT/%TESTNUMBER - - -diff --git a/tests/data/test436 b/tests/data/test436 -index d435b5110..762ab3f91 100644 ---- a/tests/data/test436 -+++ b/tests/data/test436 -@@ -35,7 +35,7 @@ XDG_CONFIG_HOME= - - Find .curlrc in .config/curlrc via CURL_HOME - -- -+ - %HOSTIP:%HTTPPORT/%TESTNUMBER - - -diff --git a/tests/data/test437 b/tests/data/test437 -index f12052d24..0f781e0b9 100644 ---- a/tests/data/test437 -+++ b/tests/data/test437 -@@ -26,8 +26,9 @@ Alt-Svc: h1="[ffff::1]:8181" - # Client-side - - --debug -+Debug - alt-svc -+IPv6 - - - http -diff --git a/tests/data/test438 b/tests/data/test438 -index 4dd3b82c8..aad056aee 100644 ---- a/tests/data/test438 -+++ b/tests/data/test438 -@@ -29,8 +29,8 @@ Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0 - - - alt-svc --debug --ipv6 -+Debug -+IPv6 - - - http -diff --git a/tests/data/test439 b/tests/data/test439 -index c997a397a..43b56ea78 100644 ---- a/tests/data/test439 -+++ b/tests/data/test439 -@@ -32,7 +32,7 @@ Funny-head: yesyes - http - - --debug -+Debug - - - aws-sigv4 with query -diff --git a/tests/data/test446 b/tests/data/test446 -index b8e719dd7..7f9891256 100644 ---- a/tests/data/test446 -+++ b/tests/data/test446 -@@ -41,7 +41,7 @@ http-proxy - HSTS - proxy - https --debug -+Debug - - - CURL_HSTS_HTTP=yes -diff --git a/tests/data/test447 b/tests/data/test447 -index f514a130e..2783b750b 100644 ---- a/tests/data/test447 -+++ b/tests/data/test447 -@@ -30,7 +30,7 @@ Funny-head: yesyes - # Client-side - - --debug -+Debug - - - http -diff --git a/tests/data/test469 b/tests/data/test469 -new file mode 100644 -index 000000000..81d341cd8 ---- /dev/null -+++ b/tests/data/test469 -@@ -0,0 +1,53 @@ -+ -+ -+ -+HTTP -+ -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+!win32 -+ -+ -+http -+ -+ -+warn about Unicode quote character -+ -+ -+-H “host: %HOSTIP:%HTTPPORT/” -s -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+%hex[Warning: The argument '%e2%80%9chost:' starts with a Unicode quote where maybe an ]hex% -+Warning: ASCII " was intended? -+ -+ -+ -diff --git a/tests/data/test470 b/tests/data/test470 -new file mode 100644 -index 000000000..70e50e621 ---- /dev/null -+++ b/tests/data/test470 -@@ -0,0 +1,56 @@ -+ -+ -+ -+HTTP -+ -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+!hyper -+ -+ -+http -+ -+ -+warn about Unicode quote character read from config file -+ -+ -+-H “host:fake” -+ -+ -+%HOSTIP:%HTTPPORT --no-progress-meter -K "%LOGDIR/input%TESTNUMBER" -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+%hex[Warning: The argument '%e2%80%9chost:fake%e2%80%9d' starts with a Unicode quote where ]hex% -+Warning: maybe an ASCII " was intended? -+ -+ -+ -diff --git a/tests/data/test471 b/tests/data/test471 -new file mode 100644 -index 000000000..69ecb5e21 ---- /dev/null -+++ b/tests/data/test471 -@@ -0,0 +1,74 @@ -+ -+ -+ -+HTTP -+HTTP GET -+globbing -+{} list -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+HTTP/2 200 OK -+Content-Type: text/html -+Funny-head: swsclose -+Connection: close -+ -+crap data -+ -+ -+ -+# -+# Client-side -+ -+ -+http/2 -+http -+ -+ -+http -+ -+ -+Reject HTTP/1.1 to HTTP/2 switch on the same connection -+ -+ -+"http://%HOSTIP:%HTTPPORT/{%TESTNUMBER,%TESTNUMBER0001}" -o "%LOGDIR/dumpit#1.dump" -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+GET /%TESTNUMBER0001 HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+# curl: (1) Version mismatch (from HTTP/1 to HTTP/2) -+ -+1 -+ -+ -+ -diff --git a/tests/data/test472 b/tests/data/test472 -new file mode 100644 -index 000000000..88cc78f93 ---- /dev/null -+++ b/tests/data/test472 -@@ -0,0 +1,59 @@ -+ -+ -+ -+HTTP -+aws-sigv4 -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+Debug -+Unicode -+ -+ -+aws-sigv4 with query -+ -+ -+"http://fake.fake.fake:8000/%TESTNUMBER/a=あ" -u user:secret --aws-sigv4 "aws:amz:us-east-2:es" --connect-to fake.fake.fake:8000:%HOSTIP:%HTTPPORT -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /472/a=%e3%81%82 HTTP/1.1 -+Host: fake.fake.fake:8000 -+Authorization: AWS4-HMAC-SHA256 Credential=user/19700101/us-east-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=c63315c199922f7ee00141869a250389405d19e205057249fb74726d940b1fc3 -+X-Amz-Date: 19700101T000000Z -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+ -diff --git a/tests/data/test473 b/tests/data/test473 -new file mode 100644 -index 000000000..874813c4e ---- /dev/null -+++ b/tests/data/test473 -@@ -0,0 +1,62 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 301 funky chunky! -+Server: fakeit/0.9 fakeitbad/1.0 -+Location: /redirected -+Transfer-Encoding: chunked -+Trailer: chunky-trailer -+Connection: mooo -+ETag: W/"asdf" -+ -+40 -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -+30 -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -+21;heresatest=moooo -+cccccccccccccccccccccccccccccccc -+ -+0 -+chunky-trailer: header data -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+Check if --etag-save saved correct etag to a file on 301 -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --etag-save %LOGDIR/etag%TESTNUMBER -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+W/"asdf" -+ -+ -+ -+ -diff --git a/tests/data/test474 b/tests/data/test474 -new file mode 100644 -index 000000000..37e0805b5 ---- /dev/null -+++ b/tests/data/test474 -@@ -0,0 +1,52 @@ -+ -+ -+ -+-w -+--write-out -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 301 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 0 -+Connection: close -+Content-Type: text/html -+Location: https://%HOSTIP:%HTTPSPORT/%TESTNUMBER0002 -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 0 -+Connection: close -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+https -+ -+ -+-w urle.scheme after HTTP to HTTPS redirect -+ -+ -+-k -L http://%HOSTIP:%HTTPPORT/%TESTNUMBER -w "%{num_redirects} %{url_effective} %{urle.scheme}\n" -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+1 https://%HOSTIP:%HTTPSPORT/%TESTNUMBER0002 https -+ -+ -+ -diff --git a/tests/data/test475 b/tests/data/test475 -new file mode 100644 -index 000000000..75e0e6b93 ---- /dev/null -+++ b/tests/data/test475 -@@ -0,0 +1,49 @@ -+ -+ -+ -+FTP -+EPSV -+STOR -+TYPE A -+ -+ -+ -+# Client-side -+ -+ -+ftp -+ -+ -+FTP PASV upload ASCII file -+ -+ -+%if win32 -+%repeat[1750 x a line of text used for verifying this !%0d%0a]% -+%else -+%repeat[1750 x a line of text used for verifying this !%0a]% -+%endif -+ -+ -+"ftp://%HOSTIP:%FTPPORT/%TESTNUMBER;type=a" -T %LOGDIR/test%TESTNUMBER.txt -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+QUIT -+ -+ -+%repeat[1750 x a line of text used for verifying this !%0a]% -+ -+ -+USER anonymous -+PASS ftp@example.com -+PWD -+EPSV -+TYPE A -+STOR %TESTNUMBER -+QUIT -+ -+ -+ -diff --git a/tests/data/test476 b/tests/data/test476 -new file mode 100644 -index 000000000..2396d3eea ---- /dev/null -+++ b/tests/data/test476 -@@ -0,0 +1,45 @@ -+ -+ -+ -+FTP -+EPSV -+STOR -+TYPE A -+ -+ -+ -+# Client-side -+ -+ -+ftp -+ -+ -+FTP PASV upload ASCII file already using CRLF -+ -+ -+%repeat[1750 x a line of text used for verifying this !%0d%0a]% -+ -+ -+"ftp://%HOSTIP:%FTPPORT/%TESTNUMBER;type=a" -T %LOGDIR/test%TESTNUMBER.txt -+ -+ -+ -+# Verify data after the test has been "shot" -+ -+ -+QUIT -+ -+ -+%repeat[1750 x a line of text used for verifying this !%0a]% -+ -+ -+USER anonymous -+PASS ftp@example.com -+PWD -+EPSV -+TYPE A -+STOR %TESTNUMBER -+QUIT -+ -+ -+ -diff --git a/tests/data/test477 b/tests/data/test477 -new file mode 100644 -index 000000000..12843918e ---- /dev/null -+++ b/tests/data/test477 -@@ -0,0 +1,67 @@ -+ -+ -+ -+HTTP -+HTTP GET -+--max-filesize -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 301 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Location: %TESTNUMBER0002 -+Accept-Ranges: bytes -+Content-Length: 26 -+Funny-head: yesyes -+ -+aaaaaaaaaaaaaaaaaaaa-foo- -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Accept-Ranges: bytes -+Content-Length: 4 -+Funny-head: yesyes -+ -+hej -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+HTTP GET with maximum filesize with a redirect sending data -+ -+ -+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --max-filesize 5 -L -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+GET /%TESTNUMBER0002 HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+ -diff --git a/tests/data/test494 b/tests/data/test494 -index 648318729..c089d75c7 100644 ---- a/tests/data/test494 -+++ b/tests/data/test494 -@@ -46,6 +46,9 @@ machine %HOSTIP login user1 password passwd1 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER user1 - PASS passwd1 -diff --git a/tests/data/test502 b/tests/data/test502 -index 0bca19c62..4e7ce38ae 100644 ---- a/tests/data/test502 -+++ b/tests/data/test502 -@@ -30,7 +30,7 @@ lib%TESTNUMBER - simple multi file:// get - - --file://%PWD/%LOGDIR/test%TESTNUMBER.txt -+file://%FILE_PWD/%LOGDIR/test%TESTNUMBER.txt - - - foo -diff --git a/tests/data/test503 b/tests/data/test503 -index 0690ad340..9fbc00b95 100644 ---- a/tests/data/test503 -+++ b/tests/data/test503 -@@ -73,7 +73,7 @@ moo - - CONNECT machine.%TESTNUMBER:%HTTPPORT HTTP/1.1 - Host: machine.%TESTNUMBER:%HTTPPORT --Proxy-Authorization: Basic dGVzdDppbmc= -+Proxy-Authorization: Basic dGVzdCUyMDppbmclNDE= - Proxy-Connection: Keep-Alive - - [DISCONNECT] -diff --git a/tests/data/test505 b/tests/data/test505 -index 6eba48936..aa26ccb5f 100644 ---- a/tests/data/test505 -+++ b/tests/data/test505 -@@ -40,6 +40,9 @@ works? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - Contents - of -diff --git a/tests/data/test508 b/tests/data/test508 -index 06cdba75f..cc1932a35 100644 ---- a/tests/data/test508 -+++ b/tests/data/test508 -@@ -41,10 +41,6 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -- --# remove CR that CURLOPT_TRANSFERTEXT added, when CharConv enabled: --s/^(this is what we post to the silly web server)\r\n/$1\n/ if($has_charconv) -- - - POST /%TESTNUMBER HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test511 b/tests/data/test511 -index adcabe8bd..7637dcede 100644 ---- a/tests/data/test511 -+++ b/tests/data/test511 -@@ -35,6 +35,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # CURLE_REMOTE_FILE_NOT_FOUND - - 78 -diff --git a/tests/data/test520 b/tests/data/test520 -index 6a27bb3f8..17d89199b 100644 ---- a/tests/data/test520 -+++ b/tests/data/test520 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/520 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - - USER anonymous -diff --git a/tests/data/test521 b/tests/data/test521 -index 1eec1bb2c..eaeb040d3 100644 ---- a/tests/data/test521 -+++ b/tests/data/test521 -@@ -9,9 +9,7 @@ CURLOPT_PORT - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -23,7 +21,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -46,6 +44,9 @@ ftp://%HOSTIP/%TESTNUMBER/ %FTPPORT - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER xxx - PASS yyy -diff --git a/tests/data/test525 b/tests/data/test525 -index 2b96a7fd9..82a85276f 100644 ---- a/tests/data/test525 -+++ b/tests/data/test525 -@@ -36,6 +36,9 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test526 b/tests/data/test526 -index 85b24d5db..3a303e9a0 100644 ---- a/tests/data/test526 -+++ b/tests/data/test526 -@@ -39,6 +39,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test527 b/tests/data/test527 -index 85b24d5db..3a303e9a0 100644 ---- a/tests/data/test527 -+++ b/tests/data/test527 -@@ -39,6 +39,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test529 b/tests/data/test529 -index 737e5018f..c92b377ef 100644 ---- a/tests/data/test529 -+++ b/tests/data/test529 -@@ -36,6 +36,9 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test531 b/tests/data/test531 -index 59501d5ea..33739ea7e 100644 ---- a/tests/data/test531 -+++ b/tests/data/test531 -@@ -39,6 +39,9 @@ don't upload this - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip all valid kinds of PORT and EPRT that curl can send - - ^PORT \d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3},\d{1,3} -diff --git a/tests/data/test532 b/tests/data/test532 -index c1d3b0b0c..128b2d880 100644 ---- a/tests/data/test532 -+++ b/tests/data/test532 -@@ -39,6 +39,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test533 b/tests/data/test533 -index 1dbceb6dd..f6467acaa 100644 ---- a/tests/data/test533 -+++ b/tests/data/test533 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test534 b/tests/data/test534 -index 0e0f35abd..87b98b5e7 100644 ---- a/tests/data/test534 -+++ b/tests/data/test534 -@@ -38,6 +38,9 @@ ftp://non-existing-host.haxx.se/path/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/path/%TE - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test539 b/tests/data/test539 -index 1fb4e1255..b774ead0b 100644 ---- a/tests/data/test539 -+++ b/tests/data/test539 -@@ -12,22 +12,14 @@ FTP - file contents - - -+ -+contents for file number two -+ -+ - - file contents -+contents for file number two - -- --total 20 --drwxr-xr-x 8 98 98 512 Oct 22 13:06 . --drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. --drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT ---r--r--r-- 1 0 1 35 Jul 16 1996 README --lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin --dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev --drwxrwxrwx 2 98 98 512 May 29 16:04 download.html --dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc --drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub --dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- - - - # Client-side -@@ -44,13 +36,16 @@ lib%TESTNUMBER - Two FTP fetches using different CURLOPT_FTP_FILEMETHOD - - --ftp://%HOSTIP:%FTPPORT/path/to/the/file/%TESTNUMBER -+ftp://%HOSTIP:%FTPPORT/path/to/the/file/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/path/to/the/file/%TESTNUMBER0001 - - - - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -@@ -63,8 +58,8 @@ RETR %TESTNUMBER - SYST - CWD / - EPSV --TYPE A --LIST path/to/the/file/%TESTNUMBER. -+SIZE path/to/the/file/%TESTNUMBER0001 -+RETR path/to/the/file/%TESTNUMBER0001 - QUIT - - -diff --git a/tests/data/test541 b/tests/data/test541 -index c0677d8ea..9492d0854 100644 ---- a/tests/data/test541 -+++ b/tests/data/test541 -@@ -40,6 +40,9 @@ works? - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - - -diff --git a/tests/data/test542 b/tests/data/test542 -index b39b1b30d..4a412c8bf 100644 ---- a/tests/data/test542 -+++ b/tests/data/test542 -@@ -44,6 +44,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - # There's no MTDM in the protocol here since this code doesn't ask for the - # time/date of the file - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test546 b/tests/data/test546 -index f8f01641a..6021b6758 100644 ---- a/tests/data/test546 -+++ b/tests/data/test546 -@@ -44,6 +44,9 @@ ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/path/%TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test557 b/tests/data/test557 -index 196377494..9d86c0ac2 100644 ---- a/tests/data/test557 -+++ b/tests/data/test557 -@@ -41,6 +41,7 @@ All curl_mprintf() signed long tests OK! - All curl_mprintf() curl_off_t tests OK! - All curl_mprintf() strings tests OK! - All float strings tests OK! -+All curl_mprintf() octal & hexadecimal tests OK! - - - -diff --git a/tests/data/test558 b/tests/data/test558 -index 06b772816..47605de0b 100644 ---- a/tests/data/test558 -+++ b/tests/data/test558 -@@ -17,7 +17,7 @@ none - - - TrackMemory --ipv6 -+IPv6 - - # tool is what to use instead of 'curl' - -diff --git a/tests/data/test562 b/tests/data/test562 -index d1793891d..c2cf2546c 100644 ---- a/tests/data/test562 -+++ b/tests/data/test562 -@@ -39,6 +39,9 @@ FTP a type=A URL and CURLOPT_PORT set - # There's no MTDM in the protocol here since this code doesn't ask for the - # time/date of the file - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test564 b/tests/data/test564 -index 96a6f9b1a..3b0a2ae1e 100644 ---- a/tests/data/test564 -+++ b/tests/data/test564 -@@ -45,6 +45,9 @@ proxy - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test574 b/tests/data/test574 -index 436e1828b..50d2120f0 100644 ---- a/tests/data/test574 -+++ b/tests/data/test574 -@@ -11,10 +11,8 @@ ftplistparser - - # - # Server-side -- -- -- -- -+# -+# Data is generated by the ftp server itself - - # Client-side - -@@ -35,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/fully_simulated/UNIX/*.txt - ############################################ - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 0 - -diff --git a/tests/data/test575 b/tests/data/test575 -index d51c5a08d..35b65a3d6 100644 ---- a/tests/data/test575 -+++ b/tests/data/test575 -@@ -32,6 +32,9 @@ ftp://%HOSTIP:%FTPPORT/fully_simulated/UNIX/* - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - 0 - -diff --git a/tests/data/test579 b/tests/data/test579 -index 68fce50d4..eaee6e323 100644 ---- a/tests/data/test579 -+++ b/tests/data/test579 -@@ -76,14 +76,10 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER %LOGDIR/ip%TESTNUMBER - # Verify data after the test has been "shot" - - --Progress callback called with UL 0 out of 0 --Progress callback called with UL 5 out of 0 --Progress callback called with UL 0 out of 0 --Progress callback called with UL 8 out of 0 --Progress callback called with UL 16 out of 0 --Progress callback called with UL 26 out of 0 --Progress callback called with UL 61 out of 0 --Progress callback called with UL 66 out of 0 -+Progress: start UL 0/0 -+Progress: end UL 5/0 -+Progress: start UL 0/0 -+Progress: end UL 66/0 - - - -diff --git a/tests/data/test582 b/tests/data/test582 -index 194591b53..de6a1a1dd 100644 ---- a/tests/data/test582 -+++ b/tests/data/test582 -@@ -34,9 +34,6 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -- --disable -- - - - -diff --git a/tests/data/test583 b/tests/data/test583 -index 0f49cd995..c9e614bae 100644 ---- a/tests/data/test583 -+++ b/tests/data/test583 -@@ -35,9 +35,6 @@ sftp://localhost:%SSHPORT%SSH_PWD/%LOGDIR/upload%TESTNUMBER.txt %USER: %LOGDIR/s - - # Verify data after the test has been "shot" - -- --disable -- - - 0 - -diff --git a/tests/data/test586 b/tests/data/test586 -index b17a702a6..a708f3b59 100644 ---- a/tests/data/test586 -+++ b/tests/data/test586 -@@ -45,6 +45,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test587 b/tests/data/test587 -index 541df4546..c896a5b6b 100644 ---- a/tests/data/test587 -+++ b/tests/data/test587 -@@ -41,21 +41,6 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -- --s/^--------------------------[A-Za-z0-9]*/------------------------------/ --s/boundary=------------------------[A-Za-z0-9]*/boundary=----------------------------/ -- -- --POST /%TESTNUMBER HTTP/1.1 --Host: %HOSTIP:%HTTPPORT --Accept: */* --Content-Length: 780 --Content-Type: multipart/form-data; boundary=---------------------------- -- -------------------------------- --Content-Disposition: form-data; name="sendfile"; filename="postit2.c" -- -- - # CURLE_ABORTED_BY_CALLBACK (42) - - 42 -diff --git a/tests/data/test588 b/tests/data/test588 -index 9c8c5f320..d41131c42 100644 ---- a/tests/data/test588 -+++ b/tests/data/test588 -@@ -45,6 +45,9 @@ Moooooooooooo - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip off parts of the PORT and EPRT commands that might differ - - s/^PORT (.*)/PORT/ -diff --git a/tests/data/test591 b/tests/data/test591 -index d1cbf082a..10d12ca26 100644 ---- a/tests/data/test591 -+++ b/tests/data/test591 -@@ -47,6 +47,9 @@ Moooooooooooo for %TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip off parts of the PORT and EPRT commands that might differ - - s/^PORT (.*)/PORT/ -diff --git a/tests/data/test592 b/tests/data/test592 -index f77eb9a87..a6fbaf72b 100644 ---- a/tests/data/test592 -+++ b/tests/data/test592 -@@ -47,6 +47,9 @@ Moooooooooooo for %TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip off parts of the PORT and EPRT commands that might differ - - s/^PORT (.*)/PORT/ -diff --git a/tests/data/test593 b/tests/data/test593 -index 9a15a5184..5c3bdf35f 100644 ---- a/tests/data/test593 -+++ b/tests/data/test593 -@@ -47,6 +47,9 @@ Moooooooooooo for %TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip off parts of the PORT and EPRT commands that might differ - - s/^PORT (.*)/PORT/ -diff --git a/tests/data/test594 b/tests/data/test594 -index cd98f0b9d..e0dfc56e3 100644 ---- a/tests/data/test594 -+++ b/tests/data/test594 -@@ -49,6 +49,9 @@ Moooooooooooo for %TESTNUMBER - - # Verify data after the test has been "shot" - -+ -+QUIT -+ - # Strip off parts of the PORT and EPRT commands that might differ - - s/^PORT (.*)/PORT/ -diff --git a/tests/data/test595 b/tests/data/test595 -index 40ace13d5..13d6bb927 100644 ---- a/tests/data/test595 -+++ b/tests/data/test595 -@@ -43,6 +43,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER %LOGDIR/ip%TESTNUMBER - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test596 b/tests/data/test596 -index 7175c63f8..30e401df7 100644 ---- a/tests/data/test596 -+++ b/tests/data/test596 -@@ -43,6 +43,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER %LOGDIR/ip%TESTNUMBER activeftp - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - s/^(EPRT \|1\|)(.*)/$1/ - -diff --git a/tests/data/test600 b/tests/data/test600 -index f2d6510ab..40aef1c46 100644 ---- a/tests/data/test600 -+++ b/tests/data/test600 -@@ -35,8 +35,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test601 b/tests/data/test601 -index 1f01ffd87..03f95d824 100644 ---- a/tests/data/test601 -+++ b/tests/data/test601 -@@ -35,8 +35,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test602 b/tests/data/test602 -index 8894c096c..6eb9b062d 100644 ---- a/tests/data/test602 -+++ b/tests/data/test602 -@@ -36,8 +36,5 @@ for ssh upload test - Test data - for ssh upload test - -- --disable -- - - -diff --git a/tests/data/test603 b/tests/data/test603 -index e98b73d11..e422cf07a 100644 ---- a/tests/data/test603 -+++ b/tests/data/test603 -@@ -36,8 +36,5 @@ for ssh upload test - Test data - for ssh upload test - -- --disable -- - - -diff --git a/tests/data/test604 b/tests/data/test604 -index 9e129ae5a..9ac9a2338 100644 ---- a/tests/data/test604 -+++ b/tests/data/test604 -@@ -23,9 +23,6 @@ SFTP retrieval of nonexistent file - # - # Verify data after the test has been "shot" - -- --disable -- - - 78 - -diff --git a/tests/data/test605 b/tests/data/test605 -index 380b77a75..d035e64eb 100644 ---- a/tests/data/test605 -+++ b/tests/data/test605 -@@ -26,8 +26,5 @@ SCP retrieval of nonexistent file - - 78 - -- --disable -- - - -diff --git a/tests/data/test606 b/tests/data/test606 -index 85c462f0f..757192d68 100644 ---- a/tests/data/test606 -+++ b/tests/data/test606 -@@ -26,8 +26,5 @@ SFTP invalid user login - - 67 - -- --disable -- - - -diff --git a/tests/data/test607 b/tests/data/test607 -index 091a73e4c..c9718a4e5 100644 ---- a/tests/data/test607 -+++ b/tests/data/test607 -@@ -26,8 +26,5 @@ SCP invalid user login - - 67 - -- --disable -- - - -diff --git a/tests/data/test608 b/tests/data/test608 -index 157713e37..6f9ed07b9 100644 ---- a/tests/data/test608 -+++ b/tests/data/test608 -@@ -24,13 +24,10 @@ sftp - SFTP post-quote rename - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rename %PWD/%LOGDIR/file%TESTNUMBER.txt %PWD/%LOGDIR/file%TESTNUMBER-renamed.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rename %SSH_PWD/%LOGDIR/file%TESTNUMBER.txt %SSH_PWD/%LOGDIR/file%TESTNUMBER-renamed.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - - # Verify that the file was renamed properly, then rename the file back to what - # it was so the verify section works and the file can be cleaned up. -- --perl %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/file%TESTNUMBER.txt move %PWD/%LOGDIR/file%TESTNUMBER-renamed.txt %PWD/%LOGDIR/file%TESTNUMBER.txt -- - - Test file for rename test - -@@ -42,8 +39,8 @@ Test file for rename test - - Test file for rename test - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/file%TESTNUMBER.txt move %PWD/%LOGDIR/file%TESTNUMBER-renamed.txt %PWD/%LOGDIR/file%TESTNUMBER.txt -+ - - -diff --git a/tests/data/test609 b/tests/data/test609 -index 3b9668552..01e8981a5 100644 ---- a/tests/data/test609 -+++ b/tests/data/test609 -@@ -25,7 +25,7 @@ sftp - SFTP post-quote mkdir failure - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-mkdir %PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-mkdir %SSH_PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - - - Test file for mkdir test -@@ -38,8 +38,5 @@ Test file for mkdir test - - 21 - -- --disable -- - - -diff --git a/tests/data/test610 b/tests/data/test610 -index 0ca51f73c..4b015881f 100644 ---- a/tests/data/test610 -+++ b/tests/data/test610 -@@ -21,17 +21,14 @@ Dummy test file for rmdir test - sftp - - --perl %SRCDIR/libtest/test%TESTNUMBER.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test%TESTNUMBER.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP post-quote rmdir - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rmdir %PWD/%LOGDIR/test%TESTNUMBER.dir" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rmdir %SSH_PWD/%LOGDIR/test%TESTNUMBER.dir" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - -- --perl %SRCDIR/libtest/test%TESTNUMBER.pl gone %PWD/%LOGDIR/test%TESTNUMBER.dir -- - - Dummy test file for rmdir test - -@@ -40,8 +37,8 @@ Dummy test file for rmdir test - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test%TESTNUMBER.pl gone %PWD/%LOGDIR/test%TESTNUMBER.dir -+ - - -diff --git a/tests/data/test611 b/tests/data/test611 -index dc75e20d4..2123e4780 100644 ---- a/tests/data/test611 -+++ b/tests/data/test611 -@@ -21,17 +21,14 @@ Dummy test file for rename test - sftp - - --perl %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP post-quote rename - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rename %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-rename %SSH_PWD/%LOGDIR/test%TESTNUMBER.dir %SSH_PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - -- --perl %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.new -- - - Dummy test file for rename test - -@@ -40,8 +37,8 @@ Dummy test file for rename test - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.new -+ - - -diff --git a/tests/data/test612 b/tests/data/test612 -index 2c43f6a0d..40212b45a 100644 ---- a/tests/data/test612 -+++ b/tests/data/test612 -@@ -24,11 +24,8 @@ sftp - SFTP post-quote remove file - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/upload.%TESTNUMBER --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt -Q "-rm %SSH_PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/upload.%TESTNUMBER --insecure - -- --perl %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/test%TESTNUMBER.txt -- - - Dummy test file for remove test - -@@ -40,8 +37,8 @@ Dummy test file for remove test - - Dummy test file for remove test - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/test%TESTNUMBER.txt -+ - - -diff --git a/tests/data/test613 b/tests/data/test613 -index f8443efa3..42cb1ee41 100644 ---- a/tests/data/test613 -+++ b/tests/data/test613 -@@ -23,7 +23,7 @@ d????????? N U U N ??? N NN:NN asubdir - sftp - - --perl %SRCDIR/libtest/test%TESTNUMBER.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test%TESTNUMBER.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP directory retrieval -@@ -31,16 +31,13 @@ SFTP directory retrieval - - --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/ --insecure - -- --perl %SRCDIR/libtest/test%TESTNUMBER.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/curl%TESTNUMBER.out -- - - - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test%TESTNUMBER.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/curl%TESTNUMBER.out -+ - - -diff --git a/tests/data/test614 b/tests/data/test614 -index 012d6ceec..53d34137c 100644 ---- a/tests/data/test614 -+++ b/tests/data/test614 -@@ -24,24 +24,21 @@ d????????? N U U N ??? N NN:NN asubdir - sftp - - --perl %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP pre-quote chmod - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "chmod 444 %PWD/%LOGDIR/test%TESTNUMBER.dir/plainfile.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/ --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "chmod 444 %SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/plainfile.txt" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/ --insecure - -- --perl %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/curl%TESTNUMBER.out -- - - - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/curl%TESTNUMBER.out -+ - - -diff --git a/tests/data/test615 b/tests/data/test615 -index 4626d3f1e..dabca40b4 100644 ---- a/tests/data/test615 -+++ b/tests/data/test615 -@@ -14,7 +14,7 @@ FAILURE - sftp - - --perl %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test613.pl prepare %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP put remote failure -@@ -22,9 +22,6 @@ SFTP put remote failure - - --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/rofile.txt --insecure - -- --perl %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir -- - - Test data - for ssh upload test -@@ -37,8 +34,8 @@ for ssh upload test - - 9 - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test613.pl postprocess %PWD/%LOGDIR/test%TESTNUMBER.dir -+ - - -diff --git a/tests/data/test616 b/tests/data/test616 -index 0ebc73434..f76c68afa 100644 ---- a/tests/data/test616 -+++ b/tests/data/test616 -@@ -32,8 +32,5 @@ SFTP retrieval of empty file - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test617 b/tests/data/test617 -index 0ab6ced01..af0f23b09 100644 ---- a/tests/data/test617 -+++ b/tests/data/test617 -@@ -32,8 +32,5 @@ SCP retrieval of empty file - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test618 b/tests/data/test618 -index 2094768f3..0d2933b27 100644 ---- a/tests/data/test618 -+++ b/tests/data/test618 -@@ -26,9 +26,6 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - Test data - for ssh test -diff --git a/tests/data/test619 b/tests/data/test619 -index 6c3296c92..12b064d23 100644 ---- a/tests/data/test619 -+++ b/tests/data/test619 -@@ -26,9 +26,6 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - Test data - for ssh test -diff --git a/tests/data/test620 b/tests/data/test620 -index 0f32d6fdf..69641001d 100644 ---- a/tests/data/test620 -+++ b/tests/data/test620 -@@ -27,9 +27,6 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - Test data - for ssh test -diff --git a/tests/data/test621 b/tests/data/test621 -index cafd80895..683575cea 100644 ---- a/tests/data/test621 -+++ b/tests/data/test621 -@@ -27,9 +27,6 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - Test data - for ssh test -diff --git a/tests/data/test622 b/tests/data/test622 -index 014ea96d9..b210c9356 100644 ---- a/tests/data/test622 -+++ b/tests/data/test622 -@@ -36,8 +36,5 @@ for ssh upload test - - 78 - -- --disable -- - - -diff --git a/tests/data/test623 b/tests/data/test623 -index 945079b3f..55802be2a 100644 ---- a/tests/data/test623 -+++ b/tests/data/test623 -@@ -33,9 +33,6 @@ for ssh upload test - # - # Verify data after the test has been "shot" - -- --disable -- - - 25 - -diff --git a/tests/data/test624 b/tests/data/test624 -index 3a4ca4b32..4305f481a 100644 ---- a/tests/data/test624 -+++ b/tests/data/test624 -@@ -24,9 +24,6 @@ SFTP put with --ftp-create-dirs - - --ftp-create-dirs --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.dir/upload.%TESTNUMBER --insecure - -- --perl %SRCDIR/libtest/test610.pl move %PWD/%LOGDIR/test%TESTNUMBER.dir/upload.%TESTNUMBER %PWD/%LOGDIR/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.dir -- - - Test data - for ssh upload test -@@ -40,8 +37,8 @@ for ssh upload test - Test data - for ssh upload test - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl move %PWD/%LOGDIR/test%TESTNUMBER.dir/upload.%TESTNUMBER %PWD/%LOGDIR/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+ - - -diff --git a/tests/data/test625 b/tests/data/test625 -index ff7549477..29a9a1cbf 100644 ---- a/tests/data/test625 -+++ b/tests/data/test625 -@@ -24,9 +24,6 @@ SFTP put with --ftp-create-dirs twice - - --ftp-create-dirs --key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -T %LOGDIR/file%TESTNUMBER.txt sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.a/upload.%TESTNUMBER -T %LOGDIR/file%TESTNUMBER.txt sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/test%TESTNUMBER.b/upload.%TESTNUMBER --insecure - -- --perl %SRCDIR/libtest/test610.pl move %PWD/%LOGDIR/test%TESTNUMBER.a/upload.%TESTNUMBER %PWD/%LOGDIR/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.a rm %PWD/%LOGDIR/test%TESTNUMBER.b/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.b -- - - Test data - for ssh upload test -@@ -40,8 +37,8 @@ for ssh upload test - Test data - for ssh upload test - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl move %PWD/%LOGDIR/test%TESTNUMBER.a/upload.%TESTNUMBER %PWD/%LOGDIR/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.a rm %PWD/%LOGDIR/test%TESTNUMBER.b/upload.%TESTNUMBER rmdir %PWD/%LOGDIR/test%TESTNUMBER.b -+ - - -diff --git a/tests/data/test626 b/tests/data/test626 -index b963b6ded..2c74329c0 100644 ---- a/tests/data/test626 -+++ b/tests/data/test626 -@@ -35,8 +35,5 @@ Test file for rename test - - 21 - -- --disable -- - - -diff --git a/tests/data/test627 b/tests/data/test627 -index 8ebdc123c..4696209b8 100644 ---- a/tests/data/test627 -+++ b/tests/data/test627 -@@ -24,11 +24,8 @@ sftp - SFTP quote remove file with NOBODY - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -I -Q "rm %PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -I -Q "rm %SSH_PWD/%LOGDIR/file%TESTNUMBER.txt" sftp://%HOSTIP:%SSHPORT --insecure - -- --perl %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/test%TESTNUMBER.txt -- - - Dummy test file for remove test - -@@ -37,10 +34,10 @@ Dummy test file for remove test - # - # Verify data after the test has been "shot" - -- --disable -- - - -+ -+%PERL %SRCDIR/libtest/test610.pl gone %PWD/%LOGDIR/test%TESTNUMBER.txt -+ - - -diff --git a/tests/data/test628 b/tests/data/test628 -index 755181e31..a1407e4a8 100644 ---- a/tests/data/test628 -+++ b/tests/data/test628 -@@ -26,8 +26,5 @@ SFTP invalid user login (password authentication) - - 67 - -- --disable -- - - -diff --git a/tests/data/test629 b/tests/data/test629 -index 6bf42f4a6..e413e2c66 100644 ---- a/tests/data/test629 -+++ b/tests/data/test629 -@@ -26,8 +26,5 @@ SCP invalid user login (password authentication) - - 67 - -- --disable -- - - -diff --git a/tests/data/test630 b/tests/data/test630 -index 8a5c44388..3ab532b91 100644 ---- a/tests/data/test630 -+++ b/tests/data/test630 -@@ -27,8 +27,5 @@ SFTP incorrect host key - - 60 - -- --disable -- - - -diff --git a/tests/data/test631 b/tests/data/test631 -index ebf661440..4f9669b46 100644 ---- a/tests/data/test631 -+++ b/tests/data/test631 -@@ -27,8 +27,5 @@ SCP incorrect host key - - 60 - -- --disable -- - - -diff --git a/tests/data/test633 b/tests/data/test633 -index 8f8c4352d..6a4da83b5 100644 ---- a/tests/data/test633 -+++ b/tests/data/test633 -@@ -35,8 +35,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test634 b/tests/data/test634 -index 3669a8bf9..94fd9e3d6 100644 ---- a/tests/data/test634 -+++ b/tests/data/test634 -@@ -36,8 +36,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test635 b/tests/data/test635 -index b07b5c823..11a2457ec 100644 ---- a/tests/data/test635 -+++ b/tests/data/test635 -@@ -35,8 +35,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test636 b/tests/data/test636 -index 96ffc0c13..cb0b4524e 100644 ---- a/tests/data/test636 -+++ b/tests/data/test636 -@@ -36,8 +36,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test637 b/tests/data/test637 -index df80c483a..a77cbf128 100644 ---- a/tests/data/test637 -+++ b/tests/data/test637 -@@ -37,8 +37,5 @@ for ssh test - - 36 - -- --disable -- - - -diff --git a/tests/data/test638 b/tests/data/test638 -index b41a3aecf..7734577a5 100644 ---- a/tests/data/test638 -+++ b/tests/data/test638 -@@ -23,17 +23,14 @@ Dummy test file for rename test - sftp - - --perl %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP post-quote rename * asterisk accept-fail - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-*rename %PWD/%LOGDIR/test%TESTNUMBER.dir %PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-*rename %SSH_PWD/%LOGDIR/test%TESTNUMBER.dir %SSH_PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - -- --perl %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.new -- - - Dummy test file for rename test - -@@ -42,8 +39,8 @@ Dummy test file for rename test - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.new -+ - - -diff --git a/tests/data/test639 b/tests/data/test639 -index 8105798fd..74440a4bb 100644 ---- a/tests/data/test639 -+++ b/tests/data/test639 -@@ -23,17 +23,14 @@ Dummy test file for rename test - sftp - - --perl %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+%PERL %SRCDIR/libtest/test610.pl mkdir %PWD/%LOGDIR/test%TESTNUMBER.dir - - - SFTP post-quote rename * asterisk accept-fail - - ----key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-*rename %PWD/%LOGDIR/test%TESTNUMBER-not-exists-dir %PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure -+--key %LOGDIR/server/curl_client_key --pubkey %LOGDIR/server/curl_client_key.pub -u %USER: -Q "-*rename %SSH_PWD/%LOGDIR/test%TESTNUMBER-not-exists-dir %SSH_PWD/%LOGDIR/test%TESTNUMBER.new" sftp://%HOSTIP:%SSHPORT%SSH_PWD/%LOGDIR/file%TESTNUMBER.txt --insecure - -- --perl %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.dir -- - - Dummy test file for rename test - -@@ -42,8 +39,8 @@ Dummy test file for rename test - # - # Verify data after the test has been "shot" - -- --disable -- -+ -+%PERL %SRCDIR/libtest/test610.pl rmdir %PWD/%LOGDIR/test%TESTNUMBER.dir -+ - - -diff --git a/tests/data/test640 b/tests/data/test640 -index ecfc0934f..31d2305d3 100644 ---- a/tests/data/test640 -+++ b/tests/data/test640 -@@ -34,8 +34,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test641 b/tests/data/test641 -index 828198b44..0e82dbc0a 100644 ---- a/tests/data/test641 -+++ b/tests/data/test641 -@@ -34,8 +34,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test642 b/tests/data/test642 -index ccb0c605d..a249d642b 100644 ---- a/tests/data/test642 -+++ b/tests/data/test642 -@@ -35,8 +35,5 @@ for ssh test - # - # Verify data after the test has been "shot" - -- --disable -- - - -diff --git a/tests/data/test644 b/tests/data/test644 -index fc670756c..b055763a3 100644 ---- a/tests/data/test644 -+++ b/tests/data/test644 -@@ -47,7 +47,7 @@ Funny-head: yesyes - http - - --debug -+Debug - xattr - - # simulate the xattr operations -@@ -78,6 +78,7 @@ Accept: */* - - - -+user.creator => curl - user.mime_type => text/html - user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER - -diff --git a/tests/data/test649 b/tests/data/test649 -index 7751e38f1..502e16ea5 100644 ---- a/tests/data/test649 -+++ b/tests/data/test649 -@@ -42,32 +42,12 @@ It contains at least an 8-bit byte value. - # - # Verify data after the test has been "shot" - -- --s/^--------------------------[A-Za-z0-9]*/------------------------------/ --s/boundary=------------------------[A-Za-z0-9]*/boundary=----------------------------/ -- - - EHLO %TESTNUMBER - MAIL FROM: - RCPT TO: - DATA - -- --Content-Type: multipart/mixed; boundary=---------------------------- --Mime-Version: 1.0 --From: different --To: another -- -------------------------------- --Content-Transfer-Encoding: 7bit -- --This is valid -------------------------------- --Content-Disposition: attachment; filename="test%TESTNUMBER.txt" --Content-Transfer-Encoding: 7bit -- --This is an attached file (in french: pi -- - - 26 - -diff --git a/tests/data/test656 b/tests/data/test656 -index 9478757d5..22eb6c1b2 100644 ---- a/tests/data/test656 -+++ b/tests/data/test656 -@@ -23,9 +23,6 @@ SFTP retrieval with nonexistent private key file - # - # Verify data after the test has been "shot" - -- --disable -- - - 67 - -diff --git a/tests/data/test661 b/tests/data/test661 -index 5965bd8ae..799d51e2d 100644 ---- a/tests/data/test661 -+++ b/tests/data/test661 -@@ -33,6 +33,9 @@ ftp://%HOSTIP:%FTPPORT/ - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test664 b/tests/data/test664 -index 6ef1d90cb..4a36a284a 100644 ---- a/tests/data/test664 -+++ b/tests/data/test664 -@@ -37,8 +37,5 @@ test - - 0 - -- --disable -- - - -diff --git a/tests/data/test665 b/tests/data/test665 -index bdab82945..fe020e1ac 100644 ---- a/tests/data/test665 -+++ b/tests/data/test665 -@@ -37,8 +37,5 @@ test - - 0 - -- --disable -- - - -diff --git a/tests/data/test687 b/tests/data/test687 -index 500a1dfb2..28b8bee7e 100644 ---- a/tests/data/test687 -+++ b/tests/data/test687 -@@ -29,7 +29,7 @@ Content-Type: fake/data - http - - --debug -+Debug - xattr - - # simulate the xattr operations -@@ -55,6 +55,7 @@ Accept: */* - - - -+user.creator => curl - user.mime_type => fake/data - user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER - -diff --git a/tests/data/test688 b/tests/data/test688 -index c545c4704..6fbd339fc 100644 ---- a/tests/data/test688 -+++ b/tests/data/test688 -@@ -29,7 +29,7 @@ Content-Type: fake/data - http - - --debug -+Debug - xattr - - # simulate the xattr operations -@@ -55,6 +55,7 @@ Accept: */* - - - -+user.creator => curl - user.mime_type => fake/data - user.xdg.origin.url => http://%HOSTIP:%HTTPPORT/%TESTNUMBER - -diff --git a/tests/data/test690 b/tests/data/test690 -new file mode 100644 -index 000000000..6f333381c ---- /dev/null -+++ b/tests/data/test690 -@@ -0,0 +1,67 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+-O with URL without path using trailing slash -+ -+ -+http://%HOSTIP:%HTTPPORT/ -O --output-dir %LOGDIR -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET / HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -diff --git a/tests/data/test691 b/tests/data/test691 -new file mode 100644 -index 000000000..b8a9a08af ---- /dev/null -+++ b/tests/data/test691 -@@ -0,0 +1,67 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+-O with URL with path using trailing slash -+ -+ -+http://%HOSTIP:%HTTPPORT/path/to/here/ -O --output-dir %LOGDIR -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /path/to/here/ HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -diff --git a/tests/data/test692 b/tests/data/test692 -new file mode 100644 -index 000000000..e3e49a018 ---- /dev/null -+++ b/tests/data/test692 -@@ -0,0 +1,56 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+-JO with URL without path using trailing slash -+ -+ -+http://%HOSTIP:%HTTPPORT/ -JO --output-dir %LOGDIR -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET / HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+-foo- -+ -+ -+ -diff --git a/tests/data/test706 b/tests/data/test706 -index 656b3dd8b..8fbb24ba5 100644 ---- a/tests/data/test706 -+++ b/tests/data/test706 -@@ -11,9 +11,7 @@ SOCKS4 - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -49,6 +47,9 @@ FTP dir list PASV via SOCKS4 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test707 b/tests/data/test707 -index 3ed89ec62..f22b2010e 100644 ---- a/tests/data/test707 -+++ b/tests/data/test707 -@@ -11,9 +11,7 @@ SOCKS5 - # - # Server-side - --# When doing LIST, we get the default list output hard-coded in the test --# FTP server -- -+ - total 20 - drwxr-xr-x 8 98 98 512 Oct 22 13:06 . - drwxr-xr-x 8 98 98 512 Oct 22 13:06 .. -@@ -25,7 +23,7 @@ drwxrwxrwx 2 98 98 512 May 29 16:04 download.html - dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc - drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub - dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr -- -+ - - - # -@@ -49,6 +47,9 @@ FTP dir list PASV via SOCKS5 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test711 b/tests/data/test711 -index 355ca0e51..288fcc1df 100644 ---- a/tests/data/test711 -+++ b/tests/data/test711 -@@ -43,6 +43,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test712 b/tests/data/test712 -index 7bcc2a1bb..ef64b3f5b 100644 ---- a/tests/data/test712 -+++ b/tests/data/test712 -@@ -37,6 +37,9 @@ ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --proxy socks5://%HOSTIP:%SOCKSPORT - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test713 b/tests/data/test713 -index 44820a78f..81374027f 100644 ---- a/tests/data/test713 -+++ b/tests/data/test713 -@@ -38,6 +38,9 @@ ftp://ftp.example.com/%TESTNUMBER --connect-to ::%HOSTIP:%FTPPORT --proxy socks5 - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test714 b/tests/data/test714 -index a38400bb8..6414188e6 100644 ---- a/tests/data/test714 -+++ b/tests/data/test714 -@@ -57,6 +57,9 @@ ftp://ftp.example.com.%TESTNUMBER/%TESTNUMBER --connect-to ::connect.example.com - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test715 b/tests/data/test715 -index 6f9670af5..e931e0d60 100644 ---- a/tests/data/test715 -+++ b/tests/data/test715 -@@ -59,6 +59,9 @@ ftp://ftp.example.com.%TESTNUMBER/%TESTNUMBER --connect-to ::connect.example.com - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - USER anonymous - PASS ftp@example.com -diff --git a/tests/data/test719 b/tests/data/test719 -index 63cb88886..454460983 100644 ---- a/tests/data/test719 -+++ b/tests/data/test719 -@@ -31,7 +31,7 @@ Funny-head: yesyes - # Client-side - - --ipv6 -+IPv6 - proxy - - -diff --git a/tests/data/test780 b/tests/data/test780 -new file mode 100644 -index 000000000..cdb8b711f ---- /dev/null -+++ b/tests/data/test780 -@@ -0,0 +1,81 @@ -+ -+ -+ -+HTTP -+HTTP proxy -+HSTS -+ -+ -+ -+ -+ -+# we use this as response to a CONNECT -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age = 1000 -+ -+ -+ -+ -+ -+ -+http -+http-proxy -+https -+ -+ -+HSTS -+proxy -+https -+Debug -+ -+ -+ -+CURL_HSTS_HTTP=yes -+CURL_TIME=1728465947 -+ -+ -+ -+this.hsts.example "99991001 04:47:41" -+ -+ -+ -+HSTS with updated expiry in response -+ -+ -+-x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k -+ -+ -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age = 1000 -+ -+ -+ -+ -+# Your HSTS cache. https://curl.se/docs/hsts.html -+# This file was generated by libcurl! Edit at your own risk. -+this.hsts.example "20241009 09:42:27" -+ -+ -+ -diff --git a/tests/data/test781 b/tests/data/test781 -new file mode 100644 -index 000000000..e931da4f5 ---- /dev/null -+++ b/tests/data/test781 -@@ -0,0 +1,84 @@ -+ -+ -+ -+HTTP -+HTTP proxy -+HSTS -+ -+ -+ -+ -+ -+# we use this as response to a CONNECT -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000 -+ -+ -+ -+ -+ -+ -+http -+http-proxy -+https -+ -+ -+HSTS -+proxy -+https -+Debug -+large-time -+ -+ -+ -+CURL_HSTS_HTTP=yes -+CURL_TIME=1728465947 -+ -+ -+ -+.hsts.example "20991001 04:47:41" -+this.hsts.example "99991001 04:47:41" -+ -+ -+ -+HSTS update expiry, with parent includeSubDomains domain present -+ -+ -+-x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k -+ -+ -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000 -+ -+ -+ -+ -+# Your HSTS cache. https://curl.se/docs/hsts.html -+# This file was generated by libcurl! Edit at your own risk. -+.hsts.example "20991001 04:47:41" -+this.hsts.example "20241009 09:42:27" -+ -+ -+ -diff --git a/tests/data/test782 b/tests/data/test782 -new file mode 100644 -index 000000000..ae0d74747 ---- /dev/null -+++ b/tests/data/test782 -@@ -0,0 +1,84 @@ -+ -+ -+ -+HTTP -+HTTP proxy -+HSTS -+ -+ -+ -+ -+ -+# we use this as response to a CONNECT -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000; includesubdomains -+ -+ -+ -+ -+ -+ -+http -+http-proxy -+https -+ -+ -+HSTS -+proxy -+https -+Debug -+large-time -+ -+ -+ -+CURL_HSTS_HTTP=yes -+CURL_TIME=1728465947 -+ -+ -+ -+.hsts.example "20991001 04:47:41" -+.this.hsts.example "99991001 04:47:41" -+ -+ -+ -+HSTS update expiry, with two includeSubDomains domains present -+ -+ -+-x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k -+ -+ -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000; includesubdomains -+ -+ -+ -+ -+# Your HSTS cache. https://curl.se/docs/hsts.html -+# This file was generated by libcurl! Edit at your own risk. -+.hsts.example "20991001 04:47:41" -+.this.hsts.example "20241009 09:42:27" -+ -+ -+ -diff --git a/tests/data/test783 b/tests/data/test783 -new file mode 100644 -index 000000000..dc58fa4fb ---- /dev/null -+++ b/tests/data/test783 -@@ -0,0 +1,84 @@ -+ -+ -+ -+HTTP -+HTTP proxy -+HSTS -+ -+ -+ -+ -+ -+# we use this as response to a CONNECT -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000; -+ -+ -+ -+ -+ -+ -+http -+http-proxy -+https -+ -+ -+HSTS -+proxy -+https -+Debug -+large-time -+ -+ -+ -+CURL_HSTS_HTTP=yes -+CURL_TIME=1728465947 -+ -+ -+ -+.hsts.example "20991001 04:47:41" -+.this.hsts.example "99991001 04:47:41" -+ -+ -+ -+HSTS update expiry, removing includesubdomains in update -+ -+ -+-x http://%HOSTIP:%PROXYPORT http://this.hsts.example:%HTTPSPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER -k -+ -+ -+ -+ -+ -+ -+HTTP/1.1 200 OK -+Server: fake -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake swsclose -+Content-Type: text/html -+Funny-head: yesyes -+Strict-Transport-Security: max-age=1000; -+ -+ -+ -+ -+# Your HSTS cache. https://curl.se/docs/hsts.html -+# This file was generated by libcurl! Edit at your own risk. -+.hsts.example "20991001 04:47:41" -+this.hsts.example "20241009 09:42:27" -+ -+ -+ -diff --git a/tests/data/test8 b/tests/data/test8 -index 9e5818815..e231cd7eb 100644 ---- a/tests/data/test8 -+++ b/tests/data/test8 -@@ -79,7 +79,7 @@ Set-Cookie: cookie31=%hex[%7f-junk]hex% - - - --perl -e 'if ("%HOSTIP" !~ /\.0\.0\.1$/) {print "Test only works for HOSTIPs ending with .0.0.1"; exit(1)}' -+%PERL -e 'if ("%HOSTIP" !~ /\.0\.0\.1$/) {print "Test only works for HOSTIPs ending with .0.0.1"; exit(1)}' - - - cookies -diff --git a/tests/data/test823 b/tests/data/test823 -index 18ed5fa67..a3736a6fd 100644 ---- a/tests/data/test823 -+++ b/tests/data/test823 -@@ -36,7 +36,7 @@ imap - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test831 b/tests/data/test831 -index 382432368..1ef3d45c4 100644 ---- a/tests/data/test831 -+++ b/tests/data/test831 -@@ -34,18 +34,9 @@ SSL - - IMAP NTLM graceful cancellation - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - 'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u testuser:testpass - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test832 b/tests/data/test832 -index 6001c1d45..bbbc0ac73 100644 ---- a/tests/data/test832 -+++ b/tests/data/test832 -@@ -28,7 +28,7 @@ imap - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test834 b/tests/data/test834 -index e142ca219..ccdf0d1fd 100644 ---- a/tests/data/test834 -+++ b/tests/data/test834 -@@ -45,18 +45,9 @@ SSL - - IMAP NTLM authentication with SASL downgrade - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - 'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test835 b/tests/data/test835 -index ee6ed31d1..17c8675eb 100644 ---- a/tests/data/test835 -+++ b/tests/data/test835 -@@ -39,7 +39,7 @@ imap - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test853 b/tests/data/test853 -index de5236420..3b57e7d08 100644 ---- a/tests/data/test853 -+++ b/tests/data/test853 -@@ -18,11 +18,11 @@ SLOWDOWN - - # When doing LIST, we get the default list output hard-coded in the test - # POP3 server -- -+ - 1 100 - 2 4294967400 - 3 200 -- -+ - - - # -diff --git a/tests/data/test869 b/tests/data/test869 -index 59900df08..56873e038 100644 ---- a/tests/data/test869 -+++ b/tests/data/test869 -@@ -38,7 +38,7 @@ pop3 - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test877 b/tests/data/test877 -index 250237062..e2cb4b376 100644 ---- a/tests/data/test877 -+++ b/tests/data/test877 -@@ -35,18 +35,9 @@ SSL - - POP3 NTLM graceful cancellation - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u testuser:testpass - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test878 b/tests/data/test878 -index 58c2e3007..657dc71c7 100644 ---- a/tests/data/test878 -+++ b/tests/data/test878 -@@ -29,7 +29,7 @@ pop3 - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test880 b/tests/data/test880 -index dfa2e688c..21536d81f 100644 ---- a/tests/data/test880 -+++ b/tests/data/test880 -@@ -47,18 +47,9 @@ SSL - - POP3 NTLM authentication with SASL downgrade - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test881 b/tests/data/test881 -index 7cbdf64ba..20e352788 100644 ---- a/tests/data/test881 -+++ b/tests/data/test881 -@@ -41,7 +41,7 @@ pop3 - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test907 b/tests/data/test907 -index 12d6e8289..8c24b68c4 100644 ---- a/tests/data/test907 -+++ b/tests/data/test907 -@@ -28,7 +28,7 @@ smtp - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test933 b/tests/data/test933 -index 71f389300..3c25ffa5c 100644 ---- a/tests/data/test933 -+++ b/tests/data/test933 -@@ -34,18 +34,9 @@ SSL - - SMTP NTLM graceful cancellation - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u testuser:testpass -T - - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test934 b/tests/data/test934 -index 8fd444e91..5ebf67fec 100644 ---- a/tests/data/test934 -+++ b/tests/data/test934 -@@ -28,7 +28,7 @@ smtp - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test936 b/tests/data/test936 -index f57f63ec8..723cebca3 100644 ---- a/tests/data/test936 -+++ b/tests/data/test936 -@@ -40,18 +40,9 @@ SMTP NTLM authentication with SASL downgrade - - mail body - -- --# we force our own host name, in order to make the test machine independent --CURL_GETHOSTNAME=curlhost --# we try to use the LD_PRELOAD hack, if not a debug build --LD_PRELOAD=%PWD/libtest/.libs/libhostname.so -- - - smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret -T - - -- --chkhostname curlhost -- - - - # -diff --git a/tests/data/test937 b/tests/data/test937 -index 6c361b738..bb761f854 100644 ---- a/tests/data/test937 -+++ b/tests/data/test937 -@@ -31,7 +31,7 @@ smtp - - - !SSPI --debug -+Debug - crypto - - -diff --git a/tests/data/test941 b/tests/data/test941 -index 7c87f5028..7b7669fdd 100644 ---- a/tests/data/test941 -+++ b/tests/data/test941 -@@ -26,12 +26,13 @@ To: another - - email - headers and body --with unix newlines -+with Unix newlines - meant to be - converted - with - the - --crlf option -+%repeat[650 x 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%0a]% - - - smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -T %LOGDIR/upload%TESTNUMBER --crlf -@@ -54,12 +55,13 @@ To: another - - email - headers and body --with unix newlines -+with Unix newlines - meant to be - converted - with - the - --crlf option -+%repeat[650 x 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 %0a]% - . - - -diff --git a/tests/data/test955 b/tests/data/test955 -index 24cc2b7e4..982afc352 100644 ---- a/tests/data/test955 -+++ b/tests/data/test955 -@@ -21,14 +21,12 @@ smtp - - - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support - UTF-8 based sender (local part only) - -diff --git a/tests/data/test956 b/tests/data/test956 -index 1180523bb..22bf3a14f 100644 ---- a/tests/data/test956 -+++ b/tests/data/test956 -@@ -18,14 +18,12 @@ smtp - - - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support - UTF-8 based recipient (local part only) - -diff --git a/tests/data/test957 b/tests/data/test957 -index 1b01b7e53..d49739d84 100644 ---- a/tests/data/test957 -+++ b/tests/data/test957 -@@ -19,14 +19,12 @@ smtp - - - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP VRFY without SMTPUTF8 support - UTF-8 based recipient (local part only) - -diff --git a/tests/data/test958 b/tests/data/test958 -index 3ad77fe10..ea5a2dbae 100644 ---- a/tests/data/test958 -+++ b/tests/data/test958 -@@ -19,14 +19,12 @@ smtp - - - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP external VRFY without SMTPUTF8 support - UTF-8 based recipient (local part only) - -diff --git a/tests/data/test959 b/tests/data/test959 -index 143708df8..178e0f13c 100644 ---- a/tests/data/test959 -+++ b/tests/data/test959 -@@ -20,16 +20,14 @@ REPLY MAIL 501 not fine enough - smtp - - --!idn -+!IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support - UTF-8 based sender (host part only) - -diff --git a/tests/data/test960 b/tests/data/test960 -index bcb9bf44c..2cf348eb5 100644 ---- a/tests/data/test960 -+++ b/tests/data/test960 -@@ -17,16 +17,14 @@ SMTP - smtp - - --!idn -+!IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support - UTF-8 based recipient (host part only) - -diff --git a/tests/data/test961 b/tests/data/test961 -index 750943ab4..57958a4eb 100644 ---- a/tests/data/test961 -+++ b/tests/data/test961 -@@ -18,16 +18,14 @@ VRFY - smtp - - --!idn -+!IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP external VRFY without SMTPUTF8 support - UTF-8 based recipient (host part only) - -diff --git a/tests/data/test962 b/tests/data/test962 -index 503761b46..6ac4ab08c 100644 ---- a/tests/data/test962 -+++ b/tests/data/test962 -@@ -18,16 +18,14 @@ IDN - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support - UTF-8 based sender (host part only) - -diff --git a/tests/data/test963 b/tests/data/test963 -index 1b977f007..9fe94f894 100644 ---- a/tests/data/test963 -+++ b/tests/data/test963 -@@ -18,16 +18,14 @@ IDN - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP without SMTPUTF8 support (IDN Enabled) - UTF-8 based recipient (host part only) - -diff --git a/tests/data/test964 b/tests/data/test964 -index e2d69881a..05dbda931 100644 ---- a/tests/data/test964 -+++ b/tests/data/test964 -@@ -19,16 +19,14 @@ IDN - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP external VRFY without SMTPUTF8 support (IDN Enabled) - UTF-8 based recipient (host part only) - -diff --git a/tests/data/test965 b/tests/data/test965 -index 71adef8f6..f44239e78 100644 ---- a/tests/data/test965 -+++ b/tests/data/test965 -@@ -21,16 +21,14 @@ CAPA SMTPUTF8 - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP with SMTPUTF8 support - UTF-8 based sender - -diff --git a/tests/data/test966 b/tests/data/test966 -index acc248a57..31b6c288f 100644 ---- a/tests/data/test966 -+++ b/tests/data/test966 -@@ -21,16 +21,14 @@ CAPA SMTPUTF8 - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP with SMTPUTF8 support - UTF-8 based recipient - -diff --git a/tests/data/test967 b/tests/data/test967 -index 95fb153bd..d823b4839 100644 ---- a/tests/data/test967 -+++ b/tests/data/test967 -@@ -25,16 +25,14 @@ CAPA SMTPUTF8 - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP external VRFY with SMTPUTF8 support - -diff --git a/tests/data/test968 b/tests/data/test968 -index 099f6fd29..b057be629 100644 ---- a/tests/data/test968 -+++ b/tests/data/test968 -@@ -22,16 +22,14 @@ CAPA SMTPUTF8 - smtp - - --idn -+IDN - !win32 -+codeset-utf8 - - - LC_ALL=en_US.UTF-8 - LC_CTYPE=en_US.UTF-8 - -- --perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");' -- - - SMTP VRFY with SMTPUTF8 support - -diff --git a/tests/data/test969 b/tests/data/test969 -index bb4cc316e..c7bffb9b8 100644 ---- a/tests/data/test969 -+++ b/tests/data/test969 -@@ -28,7 +28,7 @@ CAPA SMTPUTF8 - smtp - - --idn -+IDN - !win32 - - -diff --git a/tests/data/test970 b/tests/data/test970 -index 94e00df1c..989979738 100644 ---- a/tests/data/test970 -+++ b/tests/data/test970 -@@ -32,7 +32,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i - http - - --debug -+Debug - proxy - - -@@ -59,7 +59,7 @@ Accept: */* - - - --{"certs":"","content_type":"text/html","conn_id":0,"errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"HTTP","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.scheme":"http","url.user":null,"url.password":null,"url.options":null,"url.host":"%HOSTIP","url.port":"%HTTPPORT","url.path":"/%TESTNUMBER","url.query":null,"url.fragment":null,"url.zoneid":null,"urle.scheme":"http","urle.user":null,"urle.password":null,"urle.options":null,"urle.host":"%HOSTIP","urle.port":"%HTTPPORT","urle.path":"/%TESTNUMBER","urle.query":null,"urle.fragment":null,"urle.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"} -+{"certs":"","conn_id":0,"content_type":"text/html","errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"num_retries":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_posttransfer":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.fragment":null,"url.host":"127.0.0.1","url.options":null,"url.password":null,"url.path":"/%TESTNUMBER","url.port":"%HTTPPORT","url.query":null,"url.scheme":"http","url.user":null,"url.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urle.fragment":null,"urle.host":"127.0.0.1","urle.options":null,"urle.password":null,"urle.path":"/%TESTNUMBER","urle.port":"%HTTPPORT","urle.query":null,"urle.scheme":"http","urle.user":null,"urle.zoneid":null,"urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"} - - - -diff --git a/tests/data/test972 b/tests/data/test972 -index 735c95997..01bd2ed5f 100644 ---- a/tests/data/test972 -+++ b/tests/data/test972 -@@ -33,7 +33,7 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor i - http - - --debug -+Debug - proxy - - -@@ -60,7 +60,7 @@ Accept: */* - - - --{"certs":"","content_type":"text/html","conn_id":0,"errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out972","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"%HOSTIP","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"HTTP","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.scheme":"http","url.user":null,"url.password":null,"url.options":null,"url.host":"%HOSTIP","url.port":"%HTTPPORT","url.path":"/%TESTNUMBER","url.query":null,"url.fragment":null,"url.zoneid":null,"urle.scheme":"http","urle.user":null,"urle.password":null,"urle.options":null,"urle.host":"%HOSTIP","urle.port":"%HTTPPORT","urle.path":"/%TESTNUMBER","urle.query":null,"urle.fragment":null,"urle.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"} -+{"certs":"","conn_id":0,"content_type":"text/html","errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"num_retries":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_posttransfer":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.fragment":null,"url.host":"127.0.0.1","url.options":null,"url.password":null,"url.path":"/%TESTNUMBER","url.port":"%HTTPPORT","url.query":null,"url.scheme":"http","url.user":null,"url.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urle.fragment":null,"urle.host":"127.0.0.1","urle.options":null,"urle.password":null,"urle.path":"/%TESTNUMBER","urle.port":"%HTTPPORT","urle.query":null,"urle.scheme":"http","urle.user":null,"urle.zoneid":null,"urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"} - - - -diff --git a/tests/data/test973 b/tests/data/test973 -index 17748ea73..2961ce7c3 100644 ---- a/tests/data/test973 -+++ b/tests/data/test973 -@@ -66,6 +66,9 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER -L -u joe:secret - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - GET /%TESTNUMBER HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test975 b/tests/data/test975 -index 33f2559c6..ea4405263 100644 ---- a/tests/data/test975 -+++ b/tests/data/test975 -@@ -66,6 +66,9 @@ http://%HOSTIP:%HTTPPORT/%TESTNUMBER --location-trusted -u joe:secret - # - # Verify data after the test has been "shot" - -+ -+QUIT -+ - - GET /%TESTNUMBER HTTP/1.1 - Host: %HOSTIP:%HTTPPORT -diff --git a/tests/data/test99 b/tests/data/test99 -index db11a059b..b0e769a7e 100644 ---- a/tests/data/test99 -+++ b/tests/data/test99 -@@ -35,7 +35,7 @@ Funny-head: yesyes - # Client-side - - --large_file -+Largefile - - - http -diff --git a/tests/data/test993 b/tests/data/test993 -new file mode 100644 -index 000000000..01248de33 ---- /dev/null -+++ b/tests/data/test993 -@@ -0,0 +1,42 @@ -+ -+ -+ -+POP3 -+Clear Text -+LIST -+ -+ -+ -+# -+# Server-side -+ -+ -+%repeat[1000 x 95 328485%0d%0a]% -+ -+ -+# -+# Client-side -+ -+ -+pop3 -+ -+ -+POP3 LIST 1000 messages -+ -+ -+pop3://%HOSTIP:%POP3PORT/ -u user:secret -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+CAPA -+USER user -+PASS secret -+LIST -+QUIT -+ -+ -+ -diff --git a/tests/data/test994 b/tests/data/test994 -new file mode 100644 -index 000000000..e19d8c010 ---- /dev/null -+++ b/tests/data/test994 -@@ -0,0 +1,42 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+--skip-existing with globbing -+ -+ -+-o "%LOGDIR/#1" "http://%HOSTIP:%HTTPPORT/%TESTNUMBER/{hey,ho}" --skip-existing -+ -+ -+content -+ -+ -+content -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+Note: skips transfer, "%LOGDIR/hey" exists locally -+Note: skips transfer, "%LOGDIR/ho" exists locally -+ -+ -+ -diff --git a/tests/data/test995 b/tests/data/test995 -new file mode 100644 -index 000000000..f2ec85ea7 ---- /dev/null -+++ b/tests/data/test995 -@@ -0,0 +1,56 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT -+ETag: "21025-dc7-39462498" -+Accept-Ranges: bytes -+Content-Length: 6 -+Connection: close -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+--skip-existing without file present -+ -+ -+-o %LOGDIR/there http://%HOSTIP:%HTTPPORT/%TESTNUMBER --skip-existing -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+GET /%TESTNUMBER HTTP/1.1 -+Host: %HOSTIP:%HTTPPORT -+User-Agent: curl/%VERSION -+Accept: */* -+ -+ -+ -+-foo- -+ -+ -+ -diff --git a/tests/data/test996 b/tests/data/test996 -new file mode 100644 -index 000000000..7c5e63901 ---- /dev/null -+++ b/tests/data/test996 -@@ -0,0 +1,41 @@ -+ -+ -+ -+HTTP -+HTTP GET -+ -+ -+ -+# -+# Server-side -+ -+ -+ -+# -+# Client-side -+ -+ -+http -+ -+ -+--skip-existing with file present -+ -+ -+-o %LOGDIR/there http://%HOSTIP:%HTTPPORT/%TESTNUMBER --skip-existing -+ -+ -+content -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+Note: skips transfer, "%LOGDIR/there" exists locally -+ -+ -+content -+ -+ -+ -diff --git a/tests/data/test997 b/tests/data/test997 -new file mode 100644 -index 000000000..2883330f8 ---- /dev/null -+++ b/tests/data/test997 -@@ -0,0 +1,47 @@ -+ -+ -+ -+POP3 -+Clear Text -+STAT -+CUSTOMREQUEST -+RFC2449 -+ -+ -+ -+# -+# Server-side -+ -+ -+CAPA TOP USER -+ -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+pop3 -+ -+ -+POP3 retrieve STAT (CUSTOMREQUEST) -+ -+ -+pop3://%HOSTIP:%POP3PORT -u user:secret -X 'STAT' -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+CAPA -+USER user -+PASS secret -+STAT -+QUIT -+ -+ -+ -diff --git a/tests/data/test998 b/tests/data/test998 -new file mode 100644 -index 000000000..c3a8f5169 ---- /dev/null -+++ b/tests/data/test998 -@@ -0,0 +1,92 @@ -+ -+ -+ -+HTTP -+--location-trusted -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 301 redirect -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 0 -+Connection: close -+Content-Type: text/html -+Location: http://somewhere.else.example/a/path/%TESTNUMBER0002 -+ -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+HTTP/1.1 301 redirect -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 0 -+Connection: close -+Content-Type: text/html -+Location: http://somewhere.else.example/a/path/%TESTNUMBER0002 -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+proxy -+ -+ -+http -+ -+ -+HTTP with auth in URL redirected to another host -+ -+ -+-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER --location-trusted -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+QUIT -+ -+ -+GET http://somwhere.example/998 HTTP/1.1 -+Host: somwhere.example -+Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg== -+User-Agent: curl/%VERSION -+Accept: */* -+Proxy-Connection: Keep-Alive -+ -+GET http://somewhere.else.example/a/path/9980002 HTTP/1.1 -+Host: somewhere.else.example -+Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg== -+User-Agent: curl/%VERSION -+Accept: */* -+Proxy-Connection: Keep-Alive -+ -+ -+ -+ -diff --git a/tests/data/test999 b/tests/data/test999 -new file mode 100644 -index 000000000..990a8d09a ---- /dev/null -+++ b/tests/data/test999 -@@ -0,0 +1,81 @@ -+ -+ -+ -+HTTP -+--location-trusted -+ -+ -+ -+# -+# Server-side -+ -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+HTTP/1.1 301 redirect -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Server: test-server/fake -+Content-Length: 0 -+Connection: close -+Content-Type: text/html -+Location: http://somewhere.else.example/a/path/%TESTNUMBER0002 -+ -+HTTP/1.1 200 OK -+Date: Tue, 09 Nov 2010 14:49:00 GMT -+Content-Length: 6 -+Content-Type: text/html -+Funny-head: yesyes -+ -+-foo- -+ -+ -+ -+ -+# -+# Client-side -+ -+ -+proxy -+ -+ -+http -+ -+ -+HTTP with auth in first URL but not second -+ -+ -+-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER http://somewhere.else.example/%TESTNUMBER -+ -+ -+ -+# -+# Verify data after the test has been "shot" -+ -+ -+QUIT -+ -+ -+GET http://somwhere.example/%TESTNUMBER HTTP/1.1 -+Host: somwhere.example -+Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg== -+User-Agent: curl/%VERSION -+Accept: */* -+Proxy-Connection: Keep-Alive -+ -+GET http://somewhere.else.example/%TESTNUMBER HTTP/1.1 -+Host: somewhere.else.example -+User-Agent: curl/%VERSION -+Accept: */* -+Proxy-Connection: Keep-Alive -+ -+ -+ -+ -diff --git a/tests/devtest.pl b/tests/devtest.pl -index 99a25ab66..4fb0934e9 100755 ---- a/tests/devtest.pl -+++ b/tests/devtest.pl -@@ -110,7 +110,7 @@ sub parseprotocols { - # Initialize @protocols from the curl binary under test - # - sub init_protocols { -- for (`$CURL -V 2>/dev/null`) { -+ for (`$CURL -V 2>$dev_null`) { - if(m/^Protocols: (.*)$/) { - parseprotocols($1); - } -diff --git a/tests/dictserver.py b/tests/dictserver.py -index 0a08522f4..c28a22e5b 100755 ---- a/tests/dictserver.py -+++ b/tests/dictserver.py -@@ -24,7 +24,7 @@ - # - ########################################################################### - # --""" DICT server """ -+"""DICT server.""" - - from __future__ import (absolute_import, division, print_function, - unicode_literals) -@@ -37,7 +37,7 @@ import sys - from util import ClosingFileHandler - - try: # Python 2 -- import SocketServer as socketserver -+ import SocketServer as socketserver # type: ignore - except ImportError: # Python 3 - import socketserver - -@@ -50,10 +50,7 @@ VERIFIED_RSP = "WE ROOLZ: {pid}" - - - def dictserver(options): -- """ -- Starts up a TCP server with a DICT handler and serves DICT requests -- forever. -- """ -+ """Start up a TCP server with a DICT handler and serve DICT requests forever.""" - if options.pidfile: - pid = os.getpid() - # see tests/server/util.c function write_pidfile -@@ -74,13 +71,10 @@ def dictserver(options): - - - class DictHandler(socketserver.BaseRequestHandler): -- """Handler class for DICT connections. -+ """Handler class for DICT connections.""" - -- """ - def handle(self): -- """ -- Simple function which responds to all queries with a 552. -- """ -+ """Respond to all queries with a 552.""" - try: - # First, send a response to allow the server to continue. - rsp = "220 dictserver \n" -@@ -133,9 +127,7 @@ def get_options(): - - - def setup_logging(options): -- """ -- Set up logging from the command line options -- """ -+ """Set up logging from the command line options.""" - root_logger = logging.getLogger() - add_stdout = False - -@@ -166,16 +158,13 @@ def setup_logging(options): - - - class ScriptRC(object): -- """Enum for script return codes""" -+ """Enum for script return codes.""" -+ - SUCCESS = 0 - FAILURE = 1 - EXCEPTION = 2 - - --class ScriptException(Exception): -- pass -- -- - if __name__ == '__main__': - # Get the options from the user. - options = get_options() -@@ -186,8 +175,8 @@ if __name__ == '__main__': - # Run main script. - try: - rc = dictserver(options) -- except Exception as e: -- log.exception(e) -+ except Exception: -+ log.exception('Error running server') - rc = ScriptRC.EXCEPTION - - if options.pidfile and os.path.isfile(options.pidfile): -diff --git a/tests/ech_combos.py b/tests/ech_combos.py -new file mode 100755 -index 000000000..66daaa373 ---- /dev/null -+++ b/tests/ech_combos.py -@@ -0,0 +1,98 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+# -+# Python3 program to print all combination of size r in an array of size n. -+# This is used to generate test lines in tests/ech_test.sh. -+# This will be discarded in the process of moving from experimental, -+# but is worth preserving for the moment in case of changes to the -+# ECH command line args -+ -+def CombinationRepetitionUtil(chosen, arr, badarr, index, -+ r, start, end): -+ -+ # Current combination is ready, -+ # print it -+ if index == r: -+ # figure out if result should be good or bad and -+ # print prefix, assuming $turl does support ECH so -+ # should work if given "positive" parameters -+ res = 1 -+ j = len(chosen) - 1 -+ while res and j >= 0: -+ if chosen[j] in badarr: -+ res = 0 -+ j = j - 1 -+ print("cli_test $turl 1", res, end = " ") -+ # print combination but eliminating any runs of -+ # two identical params -+ for j in range(r): -+ if j != 0 and chosen[j] != chosen[j-1]: -+ print(chosen[j], end = " ") -+ -+ print() -+ return -+ -+ # When no more elements are -+ # there to put in chosen[] -+ if start > n: -+ return -+ -+ # Current is included, put -+ # next at next location -+ chosen[index] = arr[start] -+ -+ # Current is excluded, replace it -+ # with next (Note that i+1 is passed, -+ # but index is not changed) -+ CombinationRepetitionUtil(chosen, arr, badarr, index + 1, -+ r, start, end) -+ CombinationRepetitionUtil(chosen, arr, badarr, index, -+ r, start + 1, end) -+ -+# The main function that prints all -+# combinations of size r in arr[] of -+# size n. This function mainly uses -+# CombinationRepetitionUtil() -+def CombinationRepetition(arr, badarr, n, r): -+ -+ # A temporary array to store -+ # all combination one by one -+ chosen = [0] * r -+ -+ # Print all combination using -+ # temporary array 'chosen[]' -+ CombinationRepetitionUtil(chosen, arr, badarr, 0, r, 0, n) -+ -+# Driver code -+badarr = [ '--ech grease', '--ech false', '--ech ecl:$badecl', '--ech pn:$badpn' ] -+goodarr = [ '--ech hard', '--ech true', '--ech ecl:$goodecl', '--ech pn:$goodpn' ] -+arr = badarr + goodarr -+r = 8 -+n = len(arr) - 1 -+ -+CombinationRepetition(arr, badarr, n, r) -+ -+# This code is contributed by Vaibhav Kumar 12. -diff --git a/tests/ech_tests.sh b/tests/ech_tests.sh -new file mode 100755 -index 000000000..1746f1651 ---- /dev/null -+++ b/tests/ech_tests.sh -@@ -0,0 +1,1156 @@ -+#!/bin/bash -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+# -+ -+# Run some tests against servers we know to support ECH (CF, defo.ie, etc.). -+# as well as some we know don't do ECH but have an HTTPS RR, and finally some -+# for which neither is the case. -+ -+# TODO: Translate this into something that approximates a valid curl test:-) -+# Should be useful though even before such translation and a pile less work -+# to do this than that. The pile of work required would include making an -+# ECH-enabled server and a DoH server. For now, this is just run manually. -+# -+ -+# set -x -+ -+# Exit with an error if there's an active ech stanza in ~/.curlrc -+# as that'd likely skew some results (e.g. turning a fail into a -+# success or vice versa) -+: "${CURL_CFG_FILE=$HOME/.curlrc}" -+active_ech=$(grep ech "$CURL_CFG_FILE" | grep -v "#.*ech") -+if [[ "$active_ech" != "" ]] -+then -+ echo "You seem to have an active ECH setting in $CURL_CFG_FILE" -+ echo "That might affect results so please remove that or comment" -+ echo "it out - exiting." -+ exit 1 -+fi -+ -+ -+# Targets we expect to be ECH-enabled servers -+# for which an HTTPS RR is published. -+# structure is host:port mapped to pathname -+# TODO: add negative tests for these -+declare -A ech_targets=( -+ [my-own.net]="ech-check.php" -+ [my-own.net:8443]="ech-check.php" -+ [defo.ie]="ech-check.php" -+ [cover.defo.ie]="" -+ [draft-13.esni.defo.ie:8413]="stats" -+ [draft-13.esni.defo.ie:8414]="stats" -+ [draft-13.esni.defo.ie:9413]="" -+ [draft-13.esni.defo.ie:10413]="" -+ [draft-13.esni.defo.ie:11413]="" -+ [draft-13.esni.defo.ie:12413]="" -+ [draft-13.esni.defo.ie:12414]="" -+ [crypto.cloudflare.com]="cdn-cgi/trace" -+ [tls-ech.dev]="" -+ # this one's gone away for now (possibly temporarily) -+ # [epochbelt.com]="" -+) -+ -+# Targets we expect not to be ECH-enabled servers -+# but for which an HTTPS RR is published. -+declare -A httpsrr_targets=( -+ [ietf.org]="" -+ [rte.ie]="" -+) -+ -+# Targets we expect not to be ECH-enabled servers -+# and for which no HTTPS RR is published. -+declare -A neither_targets=( -+ [www.tcd.ie]="" -+ [jell.ie]="" -+) -+ -+# -+# Variables that can be over-ridden from environment -+# -+ -+# Top of curl test tree, assume we're there -+: "${CTOP:=.}" -+ -+# Place to put test log output -+: "${LTOP:=$CTOP/tests/ech-log/}" -+ -+# Place to stash outputs when things go wrong -+: "${BTOP:=$LTOP}" -+ -+# Time to wait for a remote access to work, 10 seconds -+: "${tout:=10s}" -+ -+# Where we find OpenSSL .so's -+: "${OSSL:=$HOME/code/openssl-local-inst}" -+ -+# Where we find wolfSSL .so's -+: "${WSSL:=$HOME/code/wolfssl/inst/lib}" -+ -+# Where we find BoringSSL .so's -+: "${BSSL:=$HOME/code/boringssl/inst/lib}" -+ -+# Where we send DoH queries when using kdig or curl -+: "${DOHSERVER:=one.one.one.one}" -+: "${DOHPATH:=dns-query}" -+ -+# Whether to send mail when bad things happen (mostly for cronjob) -+: "${DOMAIL:=no}" -+ -+# Misc vars and functions -+ -+DEFPORT=443 -+ -+function whenisitagain() -+{ -+ /bin/date -u +%Y%m%d-%H%M%S -+} -+ -+function fileage() -+{ -+ echo $(($(date +%s) - $(date +%s -r "$1"))) -+} -+ -+function hostport2host() -+{ -+ case $1 in -+ *:*) host=${1%:*} port=${1##*:};; -+ *) host=$1 port=$DEFPORT;; -+ esac -+ echo "$host" -+} -+ -+function hostport2port() -+{ -+ case $1 in -+ *:*) host=${1%:*} port=${1##*:};; -+ *) host=$1 port=$DEFPORT;; -+ esac -+ echo "$port" -+} -+ -+function cli_test() -+{ -+ # 1st param is target URL -+ turl=$1 -+ # 2nd param is 0 if we expect curl to not work or 1 if we expect it -+ # to have worked -+ curl_winorlose=$2 -+ # 3rd param is 0 if we expect ECH to not work or 1 if we expect it -+ # to have worked -+ ech_winorlose=$3 -+ # remaining params are passed to command line -+ # echparms=(${@:4}) -+ IFS=" " read -r -a echparms <<< "${@:4}" -+ -+ TMPF=$(mktemp) -+ cmd="timeout $tout $CURL ${CURL_PARAMS[*]} ${echparms[*]} $turl >$TMPF 2>&1" -+ echo "cli_test: $cmd " >> "$logfile" -+ timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" "${echparms[@]}" "$turl" >"$TMPF" 2>&1 -+ eres=$? -+ if [[ "$eres" == "124" ]] -+ then -+ allgood="no" -+ echo "cli_test: Timeout running $cmd" -+ cat "$TMPF" >> "$logfile" -+ echo "cli_test: Timeout running $cmd" >> "$logfile" -+ fi -+ if [[ "$eres" != "0" && "$curl_winorlose" == "1" ]] -+ then -+ allgood="no" -+ echo "cli_test: curl failure running $cmd" -+ cat "$TMPF" >> "$logfile" -+ echo "cli_test: curl failure running $cmd" >> "$logfile" -+ fi -+ ech_success=$(grep -c "ECH: result: status is succeeded" "$TMPF") -+ if [[ "$ech_success" == "$ech_winorlose" ]] -+ then -+ echo "cli_test ok for ${echparms[*]}" -+ else -+ allgood="no" -+ echo "cli_test: ECH failure running $cmd" -+ cat "$TMPF" >> "$logfile" -+ echo "cli_test: ECH failure running $cmd" >> "$logfile" -+ fi -+ rm -f "$TMPF" -+} -+ -+function get_ech_configlist() -+{ -+ domain=$1 -+ ecl=$(dig +short https "$domain" | grep "ech=" | sed -e 's/^.*ech=//' | sed -e 's/ .*//') -+ echo "$ecl" -+} -+ -+# start of main script -+ -+# start by assuming we have nothing we need... -+have_ossl="no" -+have_wolf="no" -+have_bssl="no" -+using_ossl="no" -+using_wolf="no" -+using_bssl="no" -+have_curl="no" -+have_dig="no" -+have_kdig="no" -+have_presout="no" -+have_portsblocked="no" -+ -+# setup logging -+NOW=$(whenisitagain) -+BINNAME=$(basename "$0" .sh) -+if [ ! -d "$LTOP" ] -+then -+ mkdir -p "$LTOP" -+fi -+if [ ! -d "$LTOP" ] -+then -+ echo "Can't see $LTOP for logs - exiting" -+ exit 1 -+fi -+logfile=$LTOP/${BINNAME}_$NOW.log -+ -+echo "-----" > "$logfile" -+echo "Running $0 at $NOW" >> "$logfile" -+echo "Running $0 at $NOW" -+ -+# check we have the binaries needed and which TLS library we'll be using -+if [ -f "$OSSL"/libssl.so ] -+then -+ have_ossl="yes" -+fi -+if [ -f "$WSSL"/libwolfssl.so ] -+then -+ have_wolf="yes" -+fi -+if [ -f "$BSSL"/libssl.so ] -+then -+ have_bssl="yes" -+fi -+CURL="$CTOP/src/curl" -+CURL_PARAMS=(-vvv --doh-url https://one.one.one.one/dns-query) -+if [ -f "$CTOP"/src/curl ] -+then -+ have_curl="yes" -+fi -+ossl_cnt=$(LD_LIBRARY_PATH=$OSSL $CURL "${CURL_PARAMS[@]}" -V 2> /dev/null | grep -c OpenSSL) -+if ((ossl_cnt == 1)) -+then -+ using_ossl="yes" -+ # setup access to our .so -+ export LD_LIBRARY_PATH=$OSSL -+fi -+bssl_cnt=$(LD_LIBRARY_PATH=$BSSL $CURL "${CURL_PARAMS[@]}" -V 2> /dev/null | grep -c BoringSSL) -+if ((bssl_cnt == 1)) -+then -+ using_bssl="yes" -+ # setup access to our .so -+ export LD_LIBRARY_PATH=$BSSL -+fi -+wolf_cnt=$($CURL "${CURL_PARAMS[@]}" -V 2> /dev/null | grep -c wolfSSL) -+if ((wolf_cnt == 1)) -+then -+ using_wolf="yes" -+ # for some reason curl+wolfSSL dislikes certs that are ok -+ # for browsers, so we'll test using "insecure" mode (-k) -+ # but that's ok here as we're only interested in ECH testing -+ CURL_PARAMS+=(-k) -+fi -+# check if we have dig and it knows https or not -+digcmd="dig +short" -+wdig=$(type -p dig) -+if [[ "$wdig" != "" ]] -+then -+ have_dig="yes" -+fi -+wkdig=$(type -p kdig) -+if [[ "$wkdig" != "" ]] -+then -+ have_kdig="yes" -+ digcmd="kdig @$DOHSERVER +https +short" -+fi -+# see if our dig version knows HTTPS -+dout=$($digcmd https defo.ie) -+if [[ $dout != "1 . "* ]] -+then -+ dout=$($digcmd -t TYPE65 defo.ie) -+ if [[ $dout == "1 . "* ]] -+ then -+ # we're good -+ have_presout="yes" -+ fi -+else -+ have_presout="yes" -+fi -+ -+# Check if ports other than 443 are blocked from this -+# vantage point (I run tests in a n/w where that's -+# sadly true sometimes;-) -+# echo "Checking if ports other than 443 are maybe blocked" -+not443testurl="https://draft-13.esni.defo.ie:9413/" -+timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" "$not443testurl" >/dev/null 2>&1 -+eres=$? -+if [[ "$eres" == "124" ]] -+then -+ echo "Timeout running curl for $not443testurl" >> "$logfile" -+ echo "Timeout running curl for $not443testurl" -+ have_portsblocked="yes" -+fi -+ -+{ -+ echo "have_ossl: $have_ossl" -+ echo "have_wolf: $have_wolf" -+ echo "have_bssl: $have_bssl" -+ echo "using_ossl: $using_ossl" -+ echo "using_wolf: $using_wolf" -+ echo "using_bssl: $using_bssl" -+ echo "have_curl: $have_curl" -+ echo "have_dig: $have_dig" -+ echo "have_kdig: $have_kdig" -+ echo "have_presout: $have_presout" -+ echo "have_portsblocked: $have_portsblocked" -+} >> "$logfile" -+ -+echo "curl: have $have_curl, cURL command: |$CURL ${CURL_PARAMS[*]}|" -+echo "ossl: have: $have_ossl, using: $using_ossl" -+echo "wolf: have: $have_wolf, using: $using_wolf" -+echo "bssl: have: $have_bssl, using: $using_bssl" -+echo "dig: $have_dig, kdig: $have_kdig, HTTPS pres format: $have_presout" -+echo "dig command: |$digcmd|" -+echo "ports != 443 blocked: $have_portsblocked" -+ -+if [[ "$have_curl" == "no" ]] -+then -+ echo "Can't proceed without curl - exiting" -+ exit 32 -+fi -+ -+allgood="yes" -+ -+skip="false" -+ -+if [[ "$skip" != "true" ]] -+then -+ -+# basic ECH good/bad -+for targ in "${!ech_targets[@]}" -+do -+ if [[ "$using_wolf" == "yes" ]] -+ then -+ case $targ in -+ "draft-13.esni.defo.ie:8414" | "tls-ech.dev" | \ -+ "crypto.cloudflare.com" | "epochbelt.com") -+ echo "Skipping $targ 'cause wolf"; continue;; -+ *) -+ ;; -+ esac -+ fi -+ host=$(hostport2host "$targ") -+ port=$(hostport2port "$targ") -+ if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]] -+ then -+ echo "Skipping $targ as ports != 443 seem blocked" -+ continue -+ fi -+ path=${ech_targets[$targ]} -+ turl="https://$host:$port/$path" -+ echo "ECH check for $turl" -+ { -+ echo "" -+ echo "ECH check for $turl" -+ } >> "$logfile" -+ timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" --ech hard "$turl" >> "$logfile" 2>&1 -+ eres=$? -+ if [[ "$eres" == "124" ]] -+ then -+ allgood="no" -+ { -+ echo "Timeout for $turl" -+ echo -e "\tTimeout for $turl" -+ echo "Timeout running curl for $host:$port/$path" -+ } >> "$logfile" -+ fi -+ if [[ "$eres" != "0" ]] -+ then -+ allgood="no" -+ echo "Error ($eres) for $turl" >> "$logfile" -+ echo -e "\tError ($eres) for $turl" -+ fi -+ echo "" >> "$logfile" -+done -+ -+# check if public_name override works (OpenSSL only) -+if [[ "$using_ossl" == "yes" ]] -+then -+ for targ in "${!ech_targets[@]}" -+ do -+ host=$(hostport2host "$targ") -+ port=$(hostport2port "$targ") -+ if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]] -+ then -+ echo "Skipping $targ as ports != 443 seem blocked" -+ continue -+ fi -+ if [[ "$host" == "crypto.cloudflare.com" ]] -+ then -+ echo "Skipping $host as they've blocked PN override" -+ continue -+ fi -+ path=${ech_targets[$targ]} -+ turl="https://$host:$port/$path" -+ echo "PN override check for $turl" -+ { -+ echo "" -+ echo "PN override check for $turl" -+ } >> "$logfile" -+ timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" --ech pn:override --ech hard "$turl" >> "$logfile" 2>&1 -+ eres=$? -+ if [[ "$eres" == "124" ]] -+ then -+ allgood="no" -+ { -+ echo "Timeout for $turl" -+ echo -e "\tTimeout for $turl" -+ echo "Timeout running curl for $host:$port/$path" -+ } >> "$logfile" -+ fi -+ if [[ "$eres" != "0" ]] -+ then -+ allgood="no" -+ echo "PN override Error ($eres) for $turl" >> "$logfile" -+ echo -e "\tPN override Error ($eres) for $turl" -+ fi -+ echo "" >> "$logfile" -+ done -+fi -+ -+for targ in "${!httpsrr_targets[@]}" -+do -+ host=$(hostport2host "$targ") -+ port=$(hostport2port "$targ") -+ if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]] -+ then -+ echo "Skipping $targ as ports != 443 seem blocked" -+ continue -+ fi -+ path=${httpsrr_targets[$targ]} -+ turl="https://$host:$port/$path" -+ echo "HTTPS RR but no ECHConfig check for $turl" -+ { -+ echo "" -+ echo "HTTPS RR but no ECHConfig check for $turl" -+ } >> "$logfile" -+ timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" --ech true "$turl" >> "$logfile" 2>&1 -+ eres=$? -+ if [[ "$eres" == "124" ]] -+ then -+ allgood="no" -+ { -+ echo "Timeout for $turl" -+ echo -e "\tTimeout for $turl" -+ echo "Timeout running curl for $host:$port/$path" -+ } >> "$logfile" -+ fi -+ if [[ "$eres" != "0" ]] -+ then -+ allgood="no" -+ echo "Error ($eres) for $turl" >> "$logfile" -+ echo -e "\tError ($eres) for $turl" -+ fi -+ echo "" >> "$logfile" -+done -+ -+for targ in "${!neither_targets[@]}" -+do -+ host=$(hostport2host "$targ") -+ port=$(hostport2port "$targ") -+ if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]] -+ then -+ echo "Skipping $targ as ports != 443 seem blocked" -+ continue -+ fi -+ path=${neither_targets[$targ]} -+ turl="https://$host:$port/$path" -+ echo "Neither HTTPS nor ECHConfig check for $turl" -+ { -+ echo "" -+ echo "Neither HTTPS nor ECHConfig check for $turl" -+ } >> "$logfile" -+ timeout "$tout" "$CURL" "${CURL_PARAMS[@]}" --ech true "$turl" >> "$logfile" 2>&1 -+ eres=$? -+ if [[ "$eres" == "124" ]] -+ then -+ allgood="no" -+ { -+ echo "Timeout for $turl" -+ echo -e "\tTimeout for $turl" -+ echo "Timeout running curl for $host:$port/$path" -+ } >> "$logfile" -+ fi -+ if [[ "$eres" != "0" ]] -+ then -+ allgood="no" -+ echo "Error ($eres) for $turl" >> "$logfile" -+ echo -e "\tError ($eres) for $turl" -+ fi -+ echo "" >> "$logfile" -+done -+ -+ -+# Check various command line options, if we're good so far -+if [[ "$using_ossl" == "yes" && "$allgood" == "yes" ]] -+then -+ # use this test URL as it'll tell us if things worked -+ turl="https://defo.ie/ech-check.php" -+ echo "cli_test with $turl" -+ echo "cli_test with $turl" >> "$logfile" -+ cli_test "$turl" 1 1 --ech true -+ cli_test "$turl" 1 0 --ech false -+ cli_test "$turl" 1 1 --ech false --ech true -+ cli_test "$turl" 1 1 --ech false --ech true --ech pn:foobar -+ cli_test "$turl" 1 1 --ech false --ech pn:foobar --ech true -+ echconfiglist=$(get_ech_configlist defo.ie) -+ cli_test "$turl" 1 1 --ech ecl:"$echconfiglist" -+ cli_test "$turl" 1 0 --ech ecl: -+fi -+ -+fi # skip -+ -+# Check combinations of command line options, if we're good so far -+# Most of this only works for OpenSSL, which is ok, as we're checking -+# the argument handling here, not the ECH protocol -+if [[ "$using_ossl" == "yes" && "$allgood" == "yes" ]] -+then -+ # ech can be hard, true, grease or false -+ # ecl:ecl can be correct, incorrect or missing -+ # ech:pn can be correct, incorrect or missing -+ # in all cases the "last" argument provided should "win" -+ # but only one of hard, true, grease or false will apply -+ turl="https://defo.ie/ech-check.php" -+ echconfiglist=$(get_ech_configlist defo.ie) -+ goodecl=$echconfiglist -+ echconfiglist=$(get_ech_configlist hidden.hoba.ie) -+ badecl=$echconfiglist -+ goodpn="cover.defo.ie" -+ badpn="hoba.ie" -+ echo "more cli_test with $turl" -+ echo "more cli_test with $turl" >> "$logfile" -+ -+ # The combinatorics here are handled via the tests/ech_combos.py script -+ # which produces all the relevant combinations or inputs and orders -+ # thereof. We have to manually assess whether or not ECH is expected to -+ # work for each case. -+ cli_test "$turl" 0 0 -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" - 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$badecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech false --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech false --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 0 --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 1 1 --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ -+ # a target URL that doesn't support ECH -+ turl="https://tcd.ie" -+ echo "cli_test with $turl" -+ echo "cli_test with $turl" >> "$logfile" -+ # the params below don't matter much here as we'll fail anyway -+ echconfiglist=$(get_ech_configlist defo.ie) -+ goodecl=$echconfiglist -+ badecl="$goodecl" -+ goodpn="tcd.ie" -+ badpn="tcd.ie" -+ cli_test "$turl" 1 0 -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$badecl" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$badecl" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech false --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech hard --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$badpn" --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech ecl:"$goodecl" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech ecl:"$goodecl" --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+ cli_test "$turl" 0 0 --ech true --ech pn:"$goodpn" -+ if [[ "$allgood" != "yes" ]]; then echo "$LINENO"; fi -+fi -+ -+ -+END=$(whenisitagain) -+echo "Finished $0 at $END" >> "$logfile" -+echo "-----" >> "$logfile" -+ -+if [[ "$allgood" == "yes" ]] -+then -+ echo "Finished $0 at $END" -+ echo "All good, log in $logfile" -+ exit 0 -+else -+ echo "Finished $0 at $END" -+ echo "NOT all good, log in $logfile" -+fi -+ -+# send a mail to root (will be fwd'd) but just once every 24 hours -+# 'cause we only really need "new" news -+itsnews="yes" -+age_of_news=0 -+if [ -f "$LTOP"/bad_runs ] -+then -+ age_of_news=$(fileage "$LTOP"/bad_runs) -+ # only consider news "new" if we haven't mailed today -+ if ((age_of_news < 24*3600)) -+ then -+ itsnews="no" -+ fi -+fi -+if [[ "$DOMAIL" == "yes" && "$itsnews" == "yes" ]] -+then -+ echo "ECH badness at $NOW" | mail -s "ECH badness at $NOW" root -+fi -+# add to list of bad runs (updating file age) -+echo "ECH badness at $NOW" >>"$LTOP"/bad_runs -+exit 2 -diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl -index 10abe418c..abe04959d 100755 ---- a/tests/ftpserver.pl -+++ b/tests/ftpserver.pl -@@ -226,7 +226,7 @@ sub ftpmsg { - - # use this, open->print->close system only to make the file - # open as little as possible, to make the test suite run -- # better on windows/cygwin -+ # better on Windows/Cygwin - } - - #********************************************************************** -@@ -488,7 +488,7 @@ sub sendcontrol { - - for(@a) { - sockfilt $_; -- portable_sleep(0.01); -+ portable_sleep($ctrldelay); - } - } - my $log; -@@ -525,7 +525,7 @@ sub senddata { - # pause between each byte - for (split(//,$l)) { - sockfiltsecondary $_; -- portable_sleep(0.01); -+ portable_sleep($datadelay); - } - } - } -@@ -670,7 +670,7 @@ sub protocolsetup { - } - } - --# Perform the disconnecgt handshake with sockfilt on the secondary connection -+# Perform the disconnect handshake with sockfilt on the secondary connection - # (the only connection we actively disconnect). - # This involves waiting for the disconnect acknowledgment after the DISC - # command, while throwing away anything else that might come in before -@@ -690,9 +690,8 @@ sub disc_handshake { - $size = hex($1); - } - -- read_datasockf(\$line, $size); -- - logmsg "> Throwing away $size bytes on closed connection\n"; -+ read_datasockf(\$line, $size); - } - elsif($line eq "DISC\n") { - logmsg "Fancy that; client wants to DISC, too\n"; -@@ -1863,12 +1862,7 @@ sub RETR_pop3 { - } - - sub LIST_pop3 { -- # This is a built-in fake-message list -- my @data = ( -- "1 100\r\n", -- "2 4294967400\r\n", # > 4 GB -- "3 200\r\n", -- ); -+ my @data = getpart("reply", "data"); - - logmsg "retrieve a message list\n"; - -@@ -2077,7 +2071,8 @@ sub CWD_ftp { - my ($folder, $fullcommand) = $_[0]; - switch_directory($folder); - if($ftptargetdir =~ /^\/fully_simulated/) { -- $ftplistparserstate = "enabled"; -+ $ftplistparserstate = "enabled"; -+ logmsg "enabled FTP list parser mode\n"; - } - else { - undef $ftplistparserstate; -@@ -2097,19 +2092,6 @@ sub PWD_ftp { - sub LIST_ftp { - # print "150 ASCII data connection for /bin/ls (193.15.23.1,59196) (0 bytes)\r\n"; - --# this is a built-in fake-dir ;-) --my @ftpdir=("total 20\r\n", --"drwxr-xr-x 8 98 98 512 Oct 22 13:06 .\r\n", --"drwxr-xr-x 8 98 98 512 Oct 22 13:06 ..\r\n", --"drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT\r\n", --"-r--r--r-- 1 0 1 35 Jul 16 1996 README\r\n", --"lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin\r\n", --"dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev\r\n", --"drwxrwxrwx 2 98 98 512 May 29 16:04 download.html\r\n", --"dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc\r\n", --"drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub\r\n", --"dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr\r\n"); -- - if($datasockf_conn eq 'no') { - if($nodataconn425) { - sendcontrol "150 Opening data connection\r\n"; -@@ -2129,15 +2111,17 @@ my @ftpdir=("total 20\r\n", - return 0; - } - -- if($ftplistparserstate) { -- @ftpdir = ftp_contentlist($ftptargetdir); -- } -- - logmsg "pass LIST data on data connection\n"; - -- if($cwd_testno) { -- loadtest("$logdir/test$cwd_testno"); -- -+ if($ftplistparserstate) { -+ # provide a synthetic response -+ my @ftpdir = ftp_contentlist($ftptargetdir); -+ # old hard-coded style -+ for(@ftpdir) { -+ senddata $_; -+ } -+ } -+ else { - my @data = getpart("reply", "data"); - for(@data) { - my $send = $_; -@@ -2147,13 +2131,6 @@ my @ftpdir=("total 20\r\n", - logmsg "send $send as data\n"; - senddata $send; - } -- $cwd_testno = 0; # forget it again -- } -- else { -- # old hard-coded style -- for(@ftpdir) { -- senddata $_; -- } - } - close_dataconn(0); - sendcontrol "226 ASCII transfer complete\r\n"; -@@ -2220,6 +2197,7 @@ sub MDTM_ftp { - - sub SIZE_ftp { - my $testno = $_[0]; -+ - if($ftplistparserstate) { - my $size = wildcard_filesize($ftptargetdir, $testno); - if($size == -1) { -@@ -2380,7 +2358,7 @@ sub RETR_ftp { - $sz = "($retrsize bytes)"; - } - -- sendcontrol "150 Binary data connection for $testno () $sz.\r\n"; -+ sendcontrol "150 Binary data connection for $testno ($testpart) $sz.\r\n"; - - for(@data) { - my $send = $_; -@@ -2830,6 +2808,7 @@ sub nodataconn_str { - # On success returns 1, otherwise zero. - # - sub customize { -+ my($cmdfile) = @_; - $ctrldelay = 0; # default is no throttling of the ctrl stream - $datadelay = 0; # default is no throttling of the data stream - $retrweirdo = 0; # default is no use of RETRWEIRDO -@@ -2889,10 +2868,15 @@ sub customize { - logmsg "FTPD: read POSTFETCH header data\n"; - $postfetch = $1; - } -+ elsif($_ =~ /SLOWDOWNDATA/) { -+ $ctrldelay=0; -+ $datadelay=0.005; -+ logmsg "FTPD: send response data with 5ms delay per byte\n"; -+ } - elsif($_ =~ /SLOWDOWN/) { -- $ctrldelay=1; -- $datadelay=1; -- logmsg "FTPD: send response with 0.01 sec delay between each byte\n"; -+ $ctrldelay=0.005; -+ $datadelay=0.005; -+ logmsg "FTPD: send response with 5ms delay between each byte\n"; - } - elsif($_ =~ /RETRWEIRDO/) { - logmsg "FTPD: instructed to use RETRWEIRDO\n"; -diff --git a/tests/getpart.pm b/tests/getpart.pm -index ed60feca5..afc1f0621 100644 ---- a/tests/getpart.pm -+++ b/tests/getpart.pm -@@ -316,7 +316,7 @@ sub compareparts { - - # NOTE: this no longer strips off carriage returns from the arrays. Is that - # really necessary? It ruins the testing of newlines. I believe it was once -- # added to enable tests on win32. -+ # added to enable tests on Windows. - - if($first ne $second) { - return 1; -@@ -332,7 +332,7 @@ sub writearray { - my ($filename, $arrayref)=@_; - - open(my $temp, ">", "$filename") || die "Failure writing file"; -- binmode($temp,":raw"); # cygwin fix by Kevin Roth -+ binmode($temp,":raw"); # Cygwin fix by Kevin Roth - for(@$arrayref) { - print $temp $_; - } -diff --git a/tests/globalconfig.pm b/tests/globalconfig.pm -index 5aad483eb..dec828e01 100644 ---- a/tests/globalconfig.pm -+++ b/tests/globalconfig.pm -@@ -38,6 +38,8 @@ BEGIN { - $automakestyle - $CURL - $CURLVERSION -+ $CURLVERNUM -+ $DATE - $has_shared - $LIBDIR - $listonly -@@ -45,6 +47,7 @@ BEGIN { - $LOGDIR - $memanalyze - $MEMDUMP -+ $perlcmd - $perl - $PIDDIR - $proxy_address -@@ -63,6 +66,8 @@ BEGIN { - %feature - %keywords - @protocols -+ $bundle -+ $dev_null - ); - } - use pathhelp qw(exe_ext); -@@ -82,12 +87,14 @@ our $run_event_based; # run curl with --test-event to test the event API - our $automakestyle; # use automake-like test status output format - our $anyway; # continue anyway, even if a test fail - our $CURLVERSION=""; # curl's reported version number -+our $CURLVERNUM=""; # curl's reported version number (without -DEV) - our $randseed = 0; # random number seed - - # paths - our $pwd = getcwd(); # current working directory - our $srcdir = $ENV{'srcdir'} || '.'; # root of the test source code --our $perl="perl -I$srcdir"; # invoke perl like this -+our $perlcmd="$^X"; -+our $perl="$perlcmd -I. -I$srcdir"; # invoke perl like this - our $LOGDIR="log"; # root of the log directory; this will be different for - # each runner in multiprocess mode - our $LIBDIR="./libtest"; -@@ -99,6 +106,8 @@ our $VCURL=$CURL; # what curl binary to use to verify the servers with - # the path to the script that analyzes the memory debug output file - our $memanalyze="$perl $srcdir/memanalyze.pl"; - our $valgrind; # path to valgrind, or empty if disabled -+our $bundle = 0; # use bundled server, libtest, unit binaries -+our $dev_null = ($^O eq 'MSWin32' ? 'NUL' : '/dev/null'); - - # paths in $LOGDIR - our $LOCKDIR = "lock"; # root of the server directory with lock files -diff --git a/tests/http/CMakeLists.txt b/tests/http/CMakeLists.txt -new file mode 100644 -index 000000000..aeedad094 ---- /dev/null -+++ b/tests/http/CMakeLists.txt -@@ -0,0 +1,62 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+ -+find_program(CADDY "caddy") # /usr/bin/caddy -+if(NOT CADDY) -+ set(CADDY "") -+endif() -+mark_as_advanced(CADDY) -+ -+find_program(VSFTPD "vsftpd") # /usr/sbin/vsftpd -+if(NOT VSFTPD) -+ set(VSFTPD "") -+endif() -+mark_as_advanced(VSFTPD) -+ -+find_program(HTTPD "apache2") # /usr/sbin/apache2 -+if(NOT HTTPD) -+ set(HTTPD "") -+endif() -+mark_as_advanced(HTTPD) -+ -+find_program(APACHECTL "apache2ctl") # /usr/sbin/apache2ctl -+if(NOT APACHECTL) -+ set(APACHECTL "") -+endif() -+mark_as_advanced(APACHECTL) -+ -+find_program(APXS "apxs") -+if(NOT APXS) -+ set(APXS "") -+endif() -+mark_as_advanced(APXS) -+ -+find_program(HTTPD_NGHTTPX "nghttpx" PATHS "/usr/bin" "/usr/local/bin") -+if(NOT HTTPD_NGHTTPX) -+ set(HTTPD_NGHTTPX "") -+endif() -+mark_as_advanced(HTTPD_NGHTTPX) -+ -+# Consumed variables: APACHECTL, APXS, CADDY, HTTPD, HTTPD_NGHTTPX, VSFTPD -+configure_file("config.ini.in" "${CMAKE_CURRENT_BINARY_DIR}/config.ini" @ONLY) -diff --git a/tests/http/Makefile.am b/tests/http/Makefile.am -index d3a219d7a..603946054 100644 ---- a/tests/http/Makefile.am -+++ b/tests/http/Makefile.am -@@ -35,10 +35,11 @@ testenv/httpd.py \ - testenv/mod_curltest/mod_curltest.c \ - testenv/nghttpx.py \ - testenv/ports.py \ -+testenv/vsftpd.py \ - testenv/ws_echo_server.py - - EXTRA_DIST = \ --config.ini.in \ -+CMakeLists.txt \ - conftest.py \ - requirements.txt \ - scorecard.py \ -@@ -57,7 +58,13 @@ test_12_reuse.py \ - test_13_proxy_auth.py \ - test_14_auth.py \ - test_15_tracing.py \ -+test_16_info.py \ -+test_17_ssl_use.py \ -+test_18_methods.py \ -+test_19_shutdown.py \ - test_20_websockets.py \ -+test_30_vsftpd.py \ -+test_31_vsftpds.py \ - $(TESTENV) - - clean-local: -diff --git a/tests/http/README.md b/tests/http/README.md -index 3a4b26394..fc3a0b22b 100644 ---- a/tests/http/README.md -+++ b/tests/http/README.md -@@ -13,7 +13,7 @@ This is an additional test suite using a combination of Apache httpd and nghttpx - The test cases and necessary files are in `tests/http`. You can invoke `pytest` from there or from the top level curl checkout and it will find all tests. - - ``` --curl> pytest -+curl> pytest test/http - platform darwin -- Python 3.9.15, pytest-6.2.0, py-1.10.0, pluggy-0.13.1 - rootdir: /Users/sei/projects/curl - collected 5 items -@@ -24,20 +24,19 @@ tests/http/test_01_basic.py ..... - Pytest takes arguments. `-v` increases its verbosity and can be used several times. `-k ` can be used to run only matching test cases. The `expr` can be something resembling a python test or just a string that needs to match test cases in their names. - - ``` --curl> pytest -vv -k test_01_02 -+curl/tests/http> pytest -vv -k test_01_02 - ``` - - runs all test cases that have `test_01_02` in their name. This does not have to be the start of the name. - - Depending on your setup, some test cases may be skipped and appear as `s` in the output. If you run pytest verbose, it will also give you the reason for skipping. - -- - # Prerequisites - - You will need: - - 1. a recent Python, the `cryptography` module and, of course, `pytest` --2. a apache httpd development version. On Debian/Ubuntu, the package `apache2-dev` has this. -+2. an apache httpd development version. On Debian/Ubuntu, the package `apache2-dev` has this. - 3. a local `curl` project build - 3. optionally, a `nghttpx` with HTTP/3 enabled or h3 test cases will be skipped. - -@@ -47,31 +46,33 @@ Via curl's `configure` script you may specify: - - * `--with-test-nghttpx=` if you have nghttpx to use somewhere outside your `$PATH`. - * `--with-test-httpd=` if you have an Apache httpd installed somewhere else. On Debian/Ubuntu it will otherwise look into `/usr/bin` and `/usr/sbin` to find those. -+ * `--with-test-caddy=` if you have a Caddy web server installed somewhere else. -+ * `--with-test-vsftpd=` if you have a vsftpd ftp server installed somewhere else. - - ## Usage Tips - - Several test cases are parameterized, for example with the HTTP version to use. If you want to run a test with a particular protocol only, use a command line like: - - ``` --curl> pytest -k "test_02_06 and h2" -+curl/tests/http> pytest -k "test_02_06 and h2" - ``` - --Several test cases can be repeated, they all have the `repeat` parameter. To make this work, you have to start `pytest` in the test directory itself (for some unknown reason). Like in: -+Test cases can be repeated, with the `pytest-repeat` module (`pip install pytest-repeat`). Like in: - - ``` --curl/tests/http> pytest -k "test_02_06 and h2" --repeat=100 -+curl/tests/http> pytest -k "test_02_06 and h2" --count=100 - ``` - - which then runs this test case a hundred times. In case of flaky tests, you can make pytest stop on the first one with: - - ``` --curl/tests/http> pytest -k "test_02_06 and h2" --repeat=100 --maxfail=1 -+curl/tests/http> pytest -k "test_02_06 and h2" --count=100 --maxfail=1 - ``` - - which allow you to inspect output and log files for the failed run. Speaking of log files, the verbosity of pytest is also used to collect curl trace output. If you specify `-v` three times, the `curl` command is started with `--trace`: - - ``` --curl/tests/http> pytest -vvv -k "test_02_06 and h2" --repeat=100 --maxfail=1 -+curl/tests/http> pytest -vvv -k "test_02_06 and h2" --count=100 --maxfail=1 - ``` - - all of curl's output and trace file are found in `tests/http/gen/curl`. -@@ -84,7 +85,7 @@ There is a lot of [`pytest` documentation](https://docs.pytest.org/) with exampl - - In `conftest.py` 3 "fixtures" are defined that are used by all test cases: - --1. `env`: the test environment. It is an instance of class `testenv/env.py:Env`. It holds all information about paths, availability of features (HTTP/3!), port numbers to use, domains and SSL certificates for those. -+1. `env`: the test environment. It is an instance of class `testenv/env.py:Env`. It holds all information about paths, availability of features (HTTP/3), port numbers to use, domains and SSL certificates for those. - 2. `httpd`: the Apache httpd instance, configured and started, then stopped at the end of the test suite. It has sites configured for the domains from `env`. It also loads a local module `mod_curltest?` and makes it available in certain locations. (more on mod_curltest below). - 3. `nghttpx`: an instance of nghttpx that provides HTTP/3 support. `nghttpx` proxies those requests to the `httpd` server. In a direct mapping, so you may access all the resources under the same path as with HTTP/2. Only the port number used for HTTP/3 requests will be different. - -diff --git a/tests/http/clients/.gitignore b/tests/http/clients/.gitignore -index f461524b3..dd6eb29e7 100644 ---- a/tests/http/clients/.gitignore -+++ b/tests/http/clients/.gitignore -@@ -3,9 +3,11 @@ - # SPDX-License-Identifier: curl - - h2-serverpush --h2-download -+hx-download -+hx-upload - ws-data - ws-pingpong - h2-upgrade-extreme - tls-session-reuse - h2-pausing -+upload-pausing -diff --git a/tests/http/clients/CMakeLists.txt b/tests/http/clients/CMakeLists.txt -new file mode 100644 -index 000000000..32c7f4d4b ---- /dev/null -+++ b/tests/http/clients/CMakeLists.txt -@@ -0,0 +1,48 @@ -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+# -+########################################################################### -+ -+add_custom_target(test-http-clients) -+ -+# Get 'check_PROGRAMS' variable -+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+ -+foreach(_target IN LISTS check_PROGRAMS) -+ set(_target_name "curlt-client-${_target}") -+ add_executable(${_target_name} EXCLUDE_FROM_ALL "${_target}.c") -+ add_dependencies(testdeps ${_target_name}) -+ add_dependencies(test-http-clients ${_target_name}) -+ target_include_directories(${_target_name} PRIVATE -+ "${PROJECT_BINARY_DIR}/lib" # for "curl_config.h" -+ "${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h" -+ ) -+ target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_LIBS}) -+ target_compile_definitions(${_target_name} PRIVATE "CURL_NO_OLDIES") -+ if(LIB_SELECTED STREQUAL LIB_STATIC AND WIN32) -+ set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB") -+ endif() -+ set_target_properties(${_target_name} PROPERTIES -+ OUTPUT_NAME "${_target}" UNITY_BUILD OFF -+ PROJECT_LABEL "Test client ${_target}") -+endforeach() -diff --git a/tests/http/clients/Makefile.am b/tests/http/clients/Makefile.am -index 8fdc190b9..935614c5f 100644 ---- a/tests/http/clients/Makefile.am -+++ b/tests/http/clients/Makefile.am -@@ -24,6 +24,7 @@ - - AUTOMAKE_OPTIONS = foreign nostdinc - -+EXTRA_DIST = CMakeLists.txt - - # Specify our include paths here, and do it relative to $(top_srcdir) and - # $(top_builddir), to ensure that these paths which belong to the library -@@ -34,8 +35,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc - - AM_CPPFLAGS = -I$(top_srcdir)/include \ - -I$(top_builddir)/lib \ -- -I$(top_srcdir)/lib \ -- -DCURL_DISABLE_DEPRECATION -+ -I$(top_srcdir)/lib - - LIBDIR = $(top_builddir)/lib - -@@ -50,16 +50,12 @@ endif - LIBS = $(BLANK_AT_MAKETIME) - - # Dependencies --if USE_EXPLICIT_LIB_DEPS --LDADD = $(LIBDIR)/libcurl.la @LIBCURL_LIBS@ --else --LDADD = $(LIBDIR)/libcurl.la --endif -+LDADD = $(LIBDIR)/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@ - - # This might hold -Werror - CFLAGS += @CURL_CFLAG_EXTRAS@ - --# Makefile.inc provides the check_PROGRAMS and COMPLICATED_EXAMPLES defines -+# Makefile.inc provides the check_PROGRAMS define - include Makefile.inc - - all: $(check_PROGRAMS) -diff --git a/tests/http/clients/Makefile.inc b/tests/http/clients/Makefile.inc -index ce7a1b6a0..c5e4e8afb 100644 ---- a/tests/http/clients/Makefile.inc -+++ b/tests/http/clients/Makefile.inc -@@ -24,10 +24,12 @@ - - # These are all libcurl example programs to be test compiled - check_PROGRAMS = \ -+ hx-download \ -+ hx-upload \ -+ h2-pausing \ - h2-serverpush \ -- h2-download \ -- ws-data \ -- ws-pingpong \ - h2-upgrade-extreme \ - tls-session-reuse \ -- h2-pausing -+ upload-pausing \ -+ ws-data \ -+ ws-pingpong -diff --git a/tests/http/clients/h2-pausing.c b/tests/http/clients/h2-pausing.c -index 40ae361f1..1fd54d4f6 100644 ---- a/tests/http/clients/h2-pausing.c -+++ b/tests/http/clients/h2-pausing.c -@@ -25,16 +25,21 @@ - * HTTP/2 download pausing - * - */ --/* This is based on the poc client of issue #11982 -+/* This is based on the PoC client of issue #11982 - */ -+#include -+ -+#include - #include - #include --#include --#include - #include --#include --#include - -+#ifndef _MSC_VER -+/* somewhat Unix-specific */ -+#include /* getopt() */ -+#endif -+ -+#ifndef _MSC_VER - #define HANDLECOUNT 2 - - static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) -@@ -74,8 +79,8 @@ static int debug_cb(CURL *handle, curl_infotype type, - if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { - if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && - conn_id >= 0) { -- curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, -- xfer_id, conn_id); -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); - } - else { - curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -@@ -141,15 +146,28 @@ static int err(void) - exit(2); - } - -+static void usage(const char *msg) -+{ -+ if(msg) -+ fprintf(stderr, "%s\n", msg); -+ fprintf(stderr, -+ "usage: [options] url\n" -+ " pause downloads with following options:\n" -+ " -V http_version (http/1.1, h2, h3) http version to use\n" -+ ); -+} -+ - struct handle - { - int idx; - int paused; - int resumed; -+ int errored; -+ int fail_write; - CURL *h; - }; - --static size_t cb(void *data, size_t size, size_t nmemb, void *clientp) -+static size_t cb(char *data, size_t size, size_t nmemb, void *clientp) - { - size_t realsize = size * nmemb; - struct handle *handle = (struct handle *) clientp; -@@ -165,15 +183,24 @@ static size_t cb(void *data, size_t size, size_t nmemb, void *clientp) - ++handle->paused; - fprintf(stderr, "INFO: [%d] write, PAUSING %d time on %lu bytes\n", - handle->idx, handle->paused, (long)realsize); -+ assert(handle->paused == 1); - return CURL_WRITEFUNC_PAUSE; - } -+ if(handle->fail_write) { -+ ++handle->errored; -+ fprintf(stderr, "INFO: [%d] FAIL write of %lu bytes, %d time\n", -+ handle->idx, (long)realsize, handle->errored); -+ return CURL_WRITEFUNC_ERROR; -+ } - fprintf(stderr, "INFO: [%d] write, accepting %lu bytes\n", - handle->idx, (long)realsize); - return realsize; - } -+#endif /* !_MSC_VER */ - - int main(int argc, char *argv[]) - { -+#ifndef _MSC_VER - struct handle handles[HANDLECOUNT]; - CURLM *multi_handle; - int i, still_running = 1, msgs_left, numfds; -@@ -186,15 +213,43 @@ int main(int argc, char *argv[]) - char *url, *host = NULL, *port = NULL; - int all_paused = 0; - int resume_round = -1; -+ int http_version = CURL_HTTP_VERSION_2_0; -+ int ch; - -- if(argc != 2) { -+ while((ch = getopt(argc, argv, "hV:")) != -1) { -+ switch(ch) { -+ case 'h': -+ usage(NULL); -+ return 2; -+ case 'V': { -+ if(!strcmp("http/1.1", optarg)) -+ http_version = CURL_HTTP_VERSION_1_1; -+ else if(!strcmp("h2", optarg)) -+ http_version = CURL_HTTP_VERSION_2_0; -+ else if(!strcmp("h3", optarg)) -+ http_version = CURL_HTTP_VERSION_3ONLY; -+ else { -+ usage("invalid http version"); -+ return 1; -+ } -+ break; -+ } -+ default: -+ usage("invalid option"); -+ return 1; -+ } -+ } -+ argc -= optind; -+ argv += optind; -+ -+ if(argc != 1) { - fprintf(stderr, "ERROR: need URL as argument\n"); - return 2; - } -- url = argv[1]; -+ url = argv[0]; - - curl_global_init(CURL_GLOBAL_DEFAULT); -- curl_global_trace("ids,time,http/2"); -+ curl_global_trace("ids,time,http/2,http/3"); - - cu = curl_url(); - if(!cu) { -@@ -214,14 +269,16 @@ int main(int argc, char *argv[]) - exit(1); - } - memset(&resolve, 0, sizeof(resolve)); -- curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, -- "%s:%s:127.0.0.1", host, port); -+ curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1", -+ host, port); - resolve = curl_slist_append(resolve, resolve_buf); - -- for(i = 0; imsg == CURLMSG_DONE) { -- for(i = 0; ieasy_handle == handles[i].h) { - if(handles[i].paused != 1 || !handles[i].resumed) { - fprintf(stderr, "ERROR: [%d] done, pauses=%d, resumed=%d, " -@@ -299,7 +364,7 @@ int main(int argc, char *argv[]) - - /* Successfully paused? */ - if(!all_paused) { -- for(i = 0; i 0 && rounds == resume_round) { - /* time to resume */ -- for(i = 0; i - */ -- - /* curl stuff */ - #include --#include - - #include - #include - #include - --/* somewhat unix-specific */ --#include --#include -- - #ifndef CURLPIPE_MULTIPLEX - #error "too old libcurl, cannot do HTTP/2 server push!" - #endif -@@ -58,7 +52,7 @@ void dump(const char *text, unsigned char *ptr, size_t size, - fprintf(stderr, "%s, %lu bytes (0x%lx)\n", - text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -189,7 +183,7 @@ static int server_push_callback(CURL *parent, - fprintf(stderr, "**** push callback approves stream %u, got %lu headers!\n", - count, (unsigned long)num_headers); - -- for(i = 0; i - */ -+#include -+ - #include - #include --#include --#include - /* #include */ - #include --#include --#include -- - - static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) - { -@@ -72,8 +69,8 @@ static int debug_cb(CURL *handle, curl_infotype type, - if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { - if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && - conn_id >= 0) { -- curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, -- xfer_id, conn_id); -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); - } - else { - curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -@@ -181,8 +178,11 @@ int main(int argc, char *argv[]) - curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb); - curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L); -- curl_msnprintf(range, sizeof(range), "%" PRIu64 "-%" PRIu64, -- UINT64_C(0), UINT64_C(16384)); -+ curl_msnprintf(range, sizeof(range), -+ "%" CURL_FORMAT_CURL_OFF_TU "-" -+ "%" CURL_FORMAT_CURL_OFF_TU, -+ (curl_off_t)0, -+ (curl_off_t)16384); - curl_easy_setopt(easy, CURLOPT_RANGE, range); - - mc = curl_multi_add_handle(multi, easy); -@@ -211,7 +211,8 @@ int main(int argc, char *argv[]) - } - - /* Check for finished handles and remove. */ -- while((msg = curl_multi_info_read(multi, &msgs_in_queue))) { -+ /* !checksrc! disable EQUALSNULL 1 */ -+ while((msg = curl_multi_info_read(multi, &msgs_in_queue)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - long status = 0; - curl_off_t xfer_id; -diff --git a/tests/http/clients/hx-download.c b/tests/http/clients/hx-download.c -new file mode 100644 -index 000000000..de50e273e ---- /dev/null -+++ b/tests/http/clients/hx-download.c -@@ -0,0 +1,532 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+/* -+ * HTTP/2 server push -+ * -+ */ -+/* curl stuff */ -+#include -+ -+#include -+#include -+#include -+ -+#ifndef _MSC_VER -+/* somewhat Unix-specific */ -+#include /* getopt() */ -+#endif -+ -+#ifndef CURLPIPE_MULTIPLEX -+#error "too old libcurl, cannot do HTTP/2 server push!" -+#endif -+ -+#ifndef _MSC_VER -+static int verbose = 1; -+ -+static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) -+{ -+ /* -+ * This is the trace look that is similar to what libcurl makes on its -+ * own. -+ */ -+ static const char * const s_infotype[] = { -+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " -+ }; -+ if(idsbuf && *idsbuf) -+ fprintf(log, "%s%s", idsbuf, s_infotype[type]); -+ else -+ fputs(s_infotype[type], log); -+} -+ -+#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] " -+#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \ -+ CURL_FORMAT_CURL_OFF_T "] " -+/* -+** callback for CURLOPT_DEBUGFUNCTION -+*/ -+static int debug_cb(CURL *handle, curl_infotype type, -+ char *data, size_t size, -+ void *userdata) -+{ -+ FILE *output = stderr; -+ static int newl = 0; -+ static int traced_data = 0; -+ char idsbuf[60]; -+ curl_off_t xfer_id, conn_id; -+ -+ (void)handle; /* not used */ -+ (void)userdata; -+ -+ if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { -+ if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && -+ conn_id >= 0) { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); -+ } -+ else { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -+ } -+ } -+ else -+ idsbuf[0] = 0; -+ -+ switch(type) { -+ case CURLINFO_HEADER_OUT: -+ if(size > 0) { -+ size_t st = 0; -+ size_t i; -+ for(i = 0; i < size - 1; i++) { -+ if(data[i] == '\n') { /* LF */ -+ if(!newl) { -+ log_line_start(output, idsbuf, type); -+ } -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ st = i + 1; -+ newl = 0; -+ } -+ } -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ } -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_TEXT: -+ case CURLINFO_HEADER_IN: -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data, size, 1, output); -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_DATA_OUT: -+ case CURLINFO_DATA_IN: -+ case CURLINFO_SSL_DATA_IN: -+ case CURLINFO_SSL_DATA_OUT: -+ if(!traced_data) { -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ fprintf(output, "[%ld bytes data]\n", (long)size); -+ newl = 0; -+ traced_data = 1; -+ } -+ break; -+ default: /* nada */ -+ newl = 0; -+ traced_data = 1; -+ break; -+ } -+ -+ return 0; -+} -+ -+struct transfer { -+ int idx; -+ CURL *easy; -+ char filename[128]; -+ FILE *out; -+ curl_off_t recv_size; -+ curl_off_t fail_at; -+ curl_off_t pause_at; -+ curl_off_t abort_at; -+ int started; -+ int paused; -+ int resumed; -+ int done; -+}; -+ -+static size_t transfer_count = 1; -+static struct transfer *transfers; -+static int forbid_reuse = 0; -+ -+static struct transfer *get_transfer_for_easy(CURL *easy) -+{ -+ size_t i; -+ for(i = 0; i < transfer_count; ++i) { -+ if(easy == transfers[i].easy) -+ return &transfers[i]; -+ } -+ return NULL; -+} -+ -+static size_t my_write_cb(char *buf, size_t nitems, size_t buflen, -+ void *userdata) -+{ -+ struct transfer *t = userdata; -+ size_t blen = (nitems * buflen); -+ size_t nwritten; -+ -+ fprintf(stderr, "[t-%d] RECV %ld bytes, total=%ld, pause_at=%ld\n", -+ t->idx, (long)blen, (long)t->recv_size, (long)t->pause_at); -+ if(!t->out) { -+ curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%u.data", -+ t->idx); -+ t->out = fopen(t->filename, "wb"); -+ if(!t->out) -+ return 0; -+ } -+ -+ if(!t->resumed && -+ t->recv_size < t->pause_at && -+ ((t->recv_size + (curl_off_t)blen) >= t->pause_at)) { -+ fprintf(stderr, "[t-%d] PAUSE\n", t->idx); -+ t->paused = 1; -+ return CURL_WRITEFUNC_PAUSE; -+ } -+ -+ nwritten = fwrite(buf, nitems, buflen, t->out); -+ if(nwritten < blen) { -+ fprintf(stderr, "[t-%d] write failure\n", t->idx); -+ return 0; -+ } -+ t->recv_size += (curl_off_t)nwritten; -+ if(t->fail_at > 0 && t->recv_size >= t->fail_at) { -+ fprintf(stderr, "[t-%d] FAIL by write callback at %ld bytes\n", -+ t->idx, (long)t->recv_size); -+ return CURL_WRITEFUNC_ERROR; -+ } -+ -+ return (size_t)nwritten; -+} -+ -+static int my_progress_cb(void *userdata, -+ curl_off_t dltotal, curl_off_t dlnow, -+ curl_off_t ultotal, curl_off_t ulnow) -+{ -+ struct transfer *t = userdata; -+ (void)ultotal; -+ (void)ulnow; -+ (void)dltotal; -+ if(t->abort_at > 0 && dlnow >= t->abort_at) { -+ fprintf(stderr, "[t-%d] ABORT by progress_cb at %ld bytes\n", -+ t->idx, (long)dlnow); -+ return 1; -+ } -+ return 0; -+} -+ -+static int setup(CURL *hnd, const char *url, struct transfer *t, -+ int http_version, struct curl_slist *host, -+ CURLSH *share, int use_earlydata) -+{ -+ curl_easy_setopt(hnd, CURLOPT_SHARE, share); -+ curl_easy_setopt(hnd, CURLOPT_URL, url); -+ curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, http_version); -+ curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); -+ curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); -+ curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, (long)(128 * 1024)); -+ curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, my_write_cb); -+ curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t); -+ curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L); -+ curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, my_progress_cb); -+ curl_easy_setopt(hnd, CURLOPT_XFERINFODATA, t); -+ if(use_earlydata) -+ curl_easy_setopt(hnd, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_EARLYDATA); -+ if(forbid_reuse) -+ curl_easy_setopt(hnd, CURLOPT_FORBID_REUSE, 1L); -+ if(host) -+ curl_easy_setopt(hnd, CURLOPT_RESOLVE, host); -+ -+ /* please be verbose */ -+ if(verbose) { -+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); -+ curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, debug_cb); -+ } -+ -+#if (CURLPIPE_MULTIPLEX > 0) -+ /* wait for pipe connection to confirm */ -+ curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); -+#endif -+ return 0; /* all is good */ -+} -+ -+static void usage(const char *msg) -+{ -+ if(msg) -+ fprintf(stderr, "%s\n", msg); -+ fprintf(stderr, -+ "usage: [options] url\n" -+ " download a url with following options:\n" -+ " -a abort paused transfer\n" -+ " -m number max parallel downloads\n" -+ " -e use TLS early data when possible\n" -+ " -f forbid connection reuse\n" -+ " -n number total downloads\n"); -+ fprintf(stderr, -+ " -A number abort transfer after `number` response bytes\n" -+ " -F number fail writing response after `number` response bytes\n" -+ " -P number pause transfer after `number` response bytes\n" -+ " -r :: resolve information\n" -+ " -V http_version (http/1.1, h2, h3) http version to use\n" -+ ); -+} -+#endif /* !_MSC_VER */ -+ -+/* -+ * Download a file over HTTP/2, take care of server push. -+ */ -+int main(int argc, char *argv[]) -+{ -+#ifndef _MSC_VER -+ CURLM *multi_handle; -+ struct CURLMsg *m; -+ CURLSH *share; -+ const char *url; -+ size_t i, n, max_parallel = 1; -+ size_t active_transfers; -+ size_t pause_offset = 0; -+ size_t abort_offset = 0; -+ size_t fail_offset = 0; -+ int abort_paused = 0, use_earlydata = 0; -+ struct transfer *t; -+ int http_version = CURL_HTTP_VERSION_2_0; -+ int ch; -+ struct curl_slist *host = NULL; -+ const char *resolve = NULL; -+ -+ while((ch = getopt(argc, argv, "aefhm:n:A:F:P:r:V:")) != -1) { -+ switch(ch) { -+ case 'h': -+ usage(NULL); -+ return 2; -+ case 'a': -+ abort_paused = 1; -+ break; -+ case 'e': -+ use_earlydata = 1; -+ break; -+ case 'f': -+ forbid_reuse = 1; -+ break; -+ case 'm': -+ max_parallel = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'n': -+ transfer_count = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'A': -+ abort_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'F': -+ fail_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'P': -+ pause_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'r': -+ resolve = optarg; -+ break; -+ case 'V': { -+ if(!strcmp("http/1.1", optarg)) -+ http_version = CURL_HTTP_VERSION_1_1; -+ else if(!strcmp("h2", optarg)) -+ http_version = CURL_HTTP_VERSION_2_0; -+ else if(!strcmp("h3", optarg)) -+ http_version = CURL_HTTP_VERSION_3ONLY; -+ else { -+ usage("invalid http version"); -+ return 1; -+ } -+ break; -+ } -+ default: -+ usage("invalid option"); -+ return 1; -+ } -+ } -+ argc -= optind; -+ argv += optind; -+ -+ curl_global_init(CURL_GLOBAL_DEFAULT); -+ curl_global_trace("ids,time,http/2,http/3"); -+ -+ if(argc != 1) { -+ usage("not enough arguments"); -+ return 2; -+ } -+ url = argv[0]; -+ -+ if(resolve) -+ host = curl_slist_append(NULL, resolve); -+ -+ share = curl_share_init(); -+ if(!share) { -+ fprintf(stderr, "error allocating share\n"); -+ return 1; -+ } -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS); -+ -+ transfers = calloc(transfer_count, sizeof(*transfers)); -+ if(!transfers) { -+ fprintf(stderr, "error allocating transfer structs\n"); -+ return 1; -+ } -+ -+ multi_handle = curl_multi_init(); -+ curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); -+ -+ active_transfers = 0; -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ t->idx = (int)i; -+ t->abort_at = (curl_off_t)abort_offset; -+ t->fail_at = (curl_off_t)fail_offset; -+ t->pause_at = (curl_off_t)pause_offset; -+ } -+ -+ n = (max_parallel < transfer_count) ? max_parallel : transfer_count; -+ for(i = 0; i < n; ++i) { -+ t = &transfers[i]; -+ t->easy = curl_easy_init(); -+ if(!t->easy || -+ setup(t->easy, url, t, http_version, host, share, use_earlydata)) { -+ fprintf(stderr, "[t-%d] FAILED setup\n", (int)i); -+ return 1; -+ } -+ curl_multi_add_handle(multi_handle, t->easy); -+ t->started = 1; -+ ++active_transfers; -+ fprintf(stderr, "[t-%d] STARTED\n", t->idx); -+ } -+ -+ do { -+ int still_running; /* keep number of running handles */ -+ CURLMcode mc = curl_multi_perform(multi_handle, &still_running); -+ -+ if(still_running) { -+ /* wait for activity, timeout or "nothing" */ -+ mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); -+ } -+ -+ if(mc) -+ break; -+ -+ do { -+ int msgq = 0; -+ m = curl_multi_info_read(multi_handle, &msgq); -+ if(m && (m->msg == CURLMSG_DONE)) { -+ CURL *e = m->easy_handle; -+ --active_transfers; -+ curl_multi_remove_handle(multi_handle, e); -+ t = get_transfer_for_easy(e); -+ if(t) { -+ t->done = 1; -+ fprintf(stderr, "[t-%d] FINISHED\n", t->idx); -+ if(use_earlydata) { -+ curl_off_t sent; -+ curl_easy_getinfo(e, CURLINFO_EARLYDATA_SENT_T, &sent); -+ fprintf(stderr, "[t-%d] EarlyData: %ld\n", t->idx, (long)sent); -+ } -+ } -+ else { -+ curl_easy_cleanup(e); -+ fprintf(stderr, "unknown FINISHED???\n"); -+ } -+ } -+ -+ -+ /* nothing happening, maintenance */ -+ if(abort_paused) { -+ /* abort paused transfers */ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->done && t->paused && t->easy) { -+ curl_multi_remove_handle(multi_handle, t->easy); -+ t->done = 1; -+ active_transfers--; -+ fprintf(stderr, "[t-%d] ABORTED\n", t->idx); -+ } -+ } -+ } -+ else { -+ /* resume one paused transfer */ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->done && t->paused) { -+ t->resumed = 1; -+ t->paused = 0; -+ curl_easy_pause(t->easy, CURLPAUSE_CONT); -+ fprintf(stderr, "[t-%d] RESUMED\n", t->idx); -+ break; -+ } -+ } -+ } -+ -+ while(active_transfers < max_parallel) { -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->started) { -+ t->easy = curl_easy_init(); -+ if(!t->easy || -+ setup(t->easy, url, t, http_version, host, share, -+ use_earlydata)) { -+ fprintf(stderr, "[t-%d] FAILED setup\n", (int)i); -+ return 1; -+ } -+ curl_multi_add_handle(multi_handle, t->easy); -+ t->started = 1; -+ ++active_transfers; -+ fprintf(stderr, "[t-%d] STARTED\n", t->idx); -+ break; -+ } -+ } -+ /* all started */ -+ if(i == transfer_count) -+ break; -+ } -+ } while(m); -+ -+ } while(active_transfers); /* as long as we have transfers going */ -+ -+ curl_multi_cleanup(multi_handle); -+ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(t->out) { -+ fclose(t->out); -+ t->out = NULL; -+ } -+ if(t->easy) { -+ curl_easy_cleanup(t->easy); -+ t->easy = NULL; -+ } -+ } -+ free(transfers); -+ -+ curl_share_cleanup(share); -+ -+ return 0; -+#else -+ (void)argc; -+ (void)argv; -+ fprintf(stderr, "Not supported with this compiler.\n"); -+ return 1; -+#endif /* !_MSC_VER */ -+} -diff --git a/tests/http/clients/hx-upload.c b/tests/http/clients/hx-upload.c -new file mode 100644 -index 000000000..06df2f4cb ---- /dev/null -+++ b/tests/http/clients/hx-upload.c -@@ -0,0 +1,617 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+/* -+ * HTTP upload tests and tweaks -+ * -+ */ -+/* curl stuff */ -+#include -+ -+#include -+#include -+#include -+ -+#ifndef _MSC_VER -+/* somewhat Unix-specific */ -+#include /* getopt() */ -+#endif -+ -+#ifndef CURLPIPE_MULTIPLEX -+#error "too old libcurl" -+#endif -+ -+#ifndef _MSC_VER -+static int verbose = 1; -+ -+static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) -+{ -+ /* -+ * This is the trace look that is similar to what libcurl makes on its -+ * own. -+ */ -+ static const char * const s_infotype[] = { -+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " -+ }; -+ if(idsbuf && *idsbuf) -+ fprintf(log, "%s%s", idsbuf, s_infotype[type]); -+ else -+ fputs(s_infotype[type], log); -+} -+ -+#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] " -+#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \ -+ CURL_FORMAT_CURL_OFF_T "] " -+/* -+** callback for CURLOPT_DEBUGFUNCTION -+*/ -+static int debug_cb(CURL *handle, curl_infotype type, -+ char *data, size_t size, -+ void *userdata) -+{ -+ FILE *output = stderr; -+ static int newl = 0; -+ static int traced_data = 0; -+ char idsbuf[60]; -+ curl_off_t xfer_id, conn_id; -+ -+ (void)handle; /* not used */ -+ (void)userdata; -+ -+ if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { -+ if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && -+ conn_id >= 0) { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); -+ } -+ else { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -+ } -+ } -+ else -+ idsbuf[0] = 0; -+ -+ switch(type) { -+ case CURLINFO_HEADER_OUT: -+ if(size > 0) { -+ size_t st = 0; -+ size_t i; -+ for(i = 0; i < size - 1; i++) { -+ if(data[i] == '\n') { /* LF */ -+ if(!newl) { -+ log_line_start(output, idsbuf, type); -+ } -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ st = i + 1; -+ newl = 0; -+ } -+ } -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ } -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_TEXT: -+ case CURLINFO_HEADER_IN: -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data, size, 1, output); -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_DATA_OUT: -+ case CURLINFO_DATA_IN: -+ case CURLINFO_SSL_DATA_IN: -+ case CURLINFO_SSL_DATA_OUT: -+ if(!traced_data) { -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ fprintf(output, "[%ld bytes data]\n", (long)size); -+ newl = 0; -+ traced_data = 1; -+ } -+ break; -+ default: /* nada */ -+ newl = 0; -+ traced_data = 1; -+ break; -+ } -+ -+ return 0; -+} -+ -+struct transfer { -+ int idx; -+ CURL *easy; -+ const char *method; -+ char filename[128]; -+ FILE *out; -+ curl_off_t send_total; -+ curl_off_t recv_size; -+ curl_off_t send_size; -+ curl_off_t fail_at; -+ curl_off_t pause_at; -+ curl_off_t abort_at; -+ int started; -+ int paused; -+ int resumed; -+ int done; -+}; -+ -+static size_t transfer_count = 1; -+static struct transfer *transfers; -+static int forbid_reuse = 0; -+ -+static struct transfer *get_transfer_for_easy(CURL *easy) -+{ -+ size_t i; -+ for(i = 0; i < transfer_count; ++i) { -+ if(easy == transfers[i].easy) -+ return &transfers[i]; -+ } -+ return NULL; -+} -+ -+static size_t my_write_cb(char *buf, size_t nitems, size_t buflen, -+ void *userdata) -+{ -+ struct transfer *t = userdata; -+ size_t blen = (nitems * buflen); -+ size_t nwritten; -+ -+ fprintf(stderr, "[t-%d] RECV %ld bytes, total=%ld, pause_at=%ld\n", -+ t->idx, (long)blen, (long)t->recv_size, (long)t->pause_at); -+ if(!t->out) { -+ curl_msnprintf(t->filename, sizeof(t->filename)-1, "download_%u.data", -+ t->idx); -+ t->out = fopen(t->filename, "wb"); -+ if(!t->out) -+ return 0; -+ } -+ -+ nwritten = fwrite(buf, nitems, buflen, t->out); -+ if(nwritten < blen) { -+ fprintf(stderr, "[t-%d] write failure\n", t->idx); -+ return 0; -+ } -+ t->recv_size += (curl_off_t)nwritten; -+ return (size_t)nwritten; -+} -+ -+static size_t my_read_cb(char *buf, size_t nitems, size_t buflen, -+ void *userdata) -+{ -+ struct transfer *t = userdata; -+ size_t blen = (nitems * buflen); -+ size_t nread; -+ -+ if(t->send_total <= t->send_size) -+ nread = 0; -+ else if((t->send_total - t->send_size) < (curl_off_t)blen) -+ nread = (size_t)(t->send_total - t->send_size); -+ else -+ nread = blen; -+ -+ fprintf(stderr, "[t-%d] SEND %ld bytes, total=%ld, pause_at=%ld\n", -+ t->idx, (long)nread, (long)t->send_total, (long)t->pause_at); -+ -+ if(!t->resumed && -+ t->send_size < t->pause_at && -+ ((t->send_size + (curl_off_t)blen) >= t->pause_at)) { -+ fprintf(stderr, "[t-%d] PAUSE\n", t->idx); -+ t->paused = 1; -+ return CURL_READFUNC_PAUSE; -+ } -+ -+ memset(buf, 'x', nread); -+ t->send_size += (curl_off_t)nread; -+ if(t->fail_at > 0 && t->send_size >= t->fail_at) { -+ fprintf(stderr, "[t-%d] ABORT by read callback at %ld bytes\n", -+ t->idx, (long)t->send_size); -+ return CURL_READFUNC_ABORT; -+ } -+ return (size_t)nread; -+} -+ -+static int my_progress_cb(void *userdata, -+ curl_off_t dltotal, curl_off_t dlnow, -+ curl_off_t ultotal, curl_off_t ulnow) -+{ -+ struct transfer *t = userdata; -+ (void)ultotal; -+ (void)dlnow; -+ (void)dltotal; -+ if(t->abort_at > 0 && ulnow >= t->abort_at) { -+ fprintf(stderr, "[t-%d] ABORT by progress_cb at %ld bytes sent\n", -+ t->idx, (long)ulnow); -+ return 1; -+ } -+ return 0; -+} -+ -+static int setup(CURL *hnd, const char *url, struct transfer *t, -+ int http_version, struct curl_slist *host, -+ CURLSH *share, int use_earlydata, int announce_length) -+{ -+ curl_easy_setopt(hnd, CURLOPT_SHARE, share); -+ curl_easy_setopt(hnd, CURLOPT_URL, url); -+ curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, http_version); -+ curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L); -+ curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L); -+ curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, (long)(128 * 1024)); -+ curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, my_write_cb); -+ curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t); -+ if(use_earlydata) -+ curl_easy_setopt(hnd, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_EARLYDATA); -+ -+ if(!t->method || !strcmp("PUT", t->method)) -+ curl_easy_setopt(hnd, CURLOPT_UPLOAD, 1L); -+ else if(!strcmp("POST", t->method)) -+ curl_easy_setopt(hnd, CURLOPT_POST, 1L); -+ else { -+ fprintf(stderr, "unsupported method '%s'\n", t->method); -+ return 1; -+ } -+ curl_easy_setopt(hnd, CURLOPT_READFUNCTION, my_read_cb); -+ curl_easy_setopt(hnd, CURLOPT_READDATA, t); -+ if(announce_length) -+ curl_easy_setopt(hnd, CURLOPT_INFILESIZE_LARGE, t->send_total); -+ -+ curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L); -+ curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, my_progress_cb); -+ curl_easy_setopt(hnd, CURLOPT_XFERINFODATA, t); -+ if(forbid_reuse) -+ curl_easy_setopt(hnd, CURLOPT_FORBID_REUSE, 1L); -+ if(host) -+ curl_easy_setopt(hnd, CURLOPT_RESOLVE, host); -+ -+ /* please be verbose */ -+ if(verbose) { -+ curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L); -+ curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, debug_cb); -+ } -+ -+#if (CURLPIPE_MULTIPLEX > 0) -+ /* wait for pipe connection to confirm */ -+ curl_easy_setopt(hnd, CURLOPT_PIPEWAIT, 1L); -+#endif -+ return 0; /* all is good */ -+} -+ -+static void usage(const char *msg) -+{ -+ if(msg) -+ fprintf(stderr, "%s\n", msg); -+ fprintf(stderr, -+ "usage: [options] url\n" -+ " upload to a url with following options:\n" -+ " -a abort paused transfer\n" -+ " -e use TLS earlydata\n" -+ " -m number max parallel uploads\n" -+ " -n number total uploads\n" -+ " -A number abort transfer after `number` request body bytes\n" -+ " -F number fail reading request body after `number` of bytes\n" -+ " -P number pause transfer after `number` request body bytes\n" -+ " -r :: resolve information\n" -+ " -S number size to upload\n" -+ " -V http_version (http/1.1, h2, h3) http version to use\n" -+ ); -+} -+#endif /* !_MSC_VER */ -+ -+/* -+ * Download a file over HTTP/2, take care of server push. -+ */ -+int main(int argc, char *argv[]) -+{ -+#ifndef _MSC_VER -+ CURLM *multi_handle; -+ struct CURLMsg *m; -+ CURLSH *share; -+ const char *url; -+ const char *method = "PUT"; -+ size_t i, n, max_parallel = 1; -+ size_t active_transfers; -+ size_t pause_offset = 0; -+ size_t abort_offset = 0; -+ size_t fail_offset = 0; -+ size_t send_total = (128 * 1024); -+ int abort_paused = 0; -+ int reuse_easy = 0; -+ int use_earlydata = 0; -+ int announce_length = 0; -+ struct transfer *t; -+ int http_version = CURL_HTTP_VERSION_2_0; -+ struct curl_slist *host = NULL; -+ const char *resolve = NULL; -+ int ch; -+ -+ while((ch = getopt(argc, argv, "aefhlm:n:A:F:M:P:r:RS:V:")) != -1) { -+ switch(ch) { -+ case 'h': -+ usage(NULL); -+ return 2; -+ case 'a': -+ abort_paused = 1; -+ break; -+ case 'e': -+ use_earlydata = 1; -+ break; -+ case 'f': -+ forbid_reuse = 1; -+ break; -+ case 'l': -+ announce_length = 1; -+ break; -+ case 'm': -+ max_parallel = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'n': -+ transfer_count = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'A': -+ abort_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'F': -+ fail_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'M': -+ method = optarg; -+ break; -+ case 'P': -+ pause_offset = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'r': -+ resolve = optarg; -+ break; -+ case 'R': -+ reuse_easy = 1; -+ break; -+ case 'S': -+ send_total = (size_t)strtol(optarg, NULL, 10); -+ break; -+ case 'V': { -+ if(!strcmp("http/1.1", optarg)) -+ http_version = CURL_HTTP_VERSION_1_1; -+ else if(!strcmp("h2", optarg)) -+ http_version = CURL_HTTP_VERSION_2_0; -+ else if(!strcmp("h3", optarg)) -+ http_version = CURL_HTTP_VERSION_3ONLY; -+ else { -+ usage("invalid http version"); -+ return 1; -+ } -+ break; -+ } -+ default: -+ usage("invalid option"); -+ return 1; -+ } -+ } -+ argc -= optind; -+ argv += optind; -+ -+ if(max_parallel > 1 && reuse_easy) { -+ usage("cannot mix -R and -P"); -+ return 2; -+ } -+ -+ curl_global_init(CURL_GLOBAL_DEFAULT); -+ curl_global_trace("ids,time,http/2,http/3"); -+ -+ if(argc != 1) { -+ usage("not enough arguments"); -+ return 2; -+ } -+ url = argv[0]; -+ -+ if(resolve) -+ host = curl_slist_append(NULL, resolve); -+ -+ share = curl_share_init(); -+ if(!share) { -+ fprintf(stderr, "error allocating share\n"); -+ return 1; -+ } -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS); -+ -+ transfers = calloc(transfer_count, sizeof(*transfers)); -+ if(!transfers) { -+ fprintf(stderr, "error allocating transfer structs\n"); -+ return 1; -+ } -+ -+ active_transfers = 0; -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ t->idx = (int)i; -+ t->method = method; -+ t->send_total = (curl_off_t)send_total; -+ t->abort_at = (curl_off_t)abort_offset; -+ t->fail_at = (curl_off_t)fail_offset; -+ t->pause_at = (curl_off_t)pause_offset; -+ } -+ -+ if(reuse_easy) { -+ CURL *easy = curl_easy_init(); -+ CURLcode rc = CURLE_OK; -+ if(!easy) { -+ fprintf(stderr, "failed to init easy handle\n"); -+ return 1; -+ } -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ t->easy = easy; -+ if(setup(t->easy, url, t, http_version, host, share, use_earlydata, -+ announce_length)) { -+ fprintf(stderr, "[t-%d] FAILED setup\n", (int)i); -+ return 1; -+ } -+ -+ fprintf(stderr, "[t-%d] STARTING\n", t->idx); -+ rc = curl_easy_perform(easy); -+ fprintf(stderr, "[t-%d] DONE -> %d\n", t->idx, rc); -+ t->easy = NULL; -+ curl_easy_reset(easy); -+ } -+ curl_easy_cleanup(easy); -+ } -+ else { -+ multi_handle = curl_multi_init(); -+ curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); -+ -+ n = (max_parallel < transfer_count) ? max_parallel : transfer_count; -+ for(i = 0; i < n; ++i) { -+ t = &transfers[i]; -+ t->easy = curl_easy_init(); -+ if(!t->easy || setup(t->easy, url, t, http_version, host, share, -+ use_earlydata, announce_length)) { -+ fprintf(stderr, "[t-%d] FAILED setup\n", (int)i); -+ return 1; -+ } -+ curl_multi_add_handle(multi_handle, t->easy); -+ t->started = 1; -+ ++active_transfers; -+ fprintf(stderr, "[t-%d] STARTED\n", t->idx); -+ } -+ -+ do { -+ int still_running; /* keep number of running handles */ -+ CURLMcode mc = curl_multi_perform(multi_handle, &still_running); -+ -+ if(still_running) { -+ /* wait for activity, timeout or "nothing" */ -+ mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL); -+ } -+ -+ if(mc) -+ break; -+ -+ do { -+ int msgq = 0; -+ m = curl_multi_info_read(multi_handle, &msgq); -+ if(m && (m->msg == CURLMSG_DONE)) { -+ CURL *e = m->easy_handle; -+ --active_transfers; -+ curl_multi_remove_handle(multi_handle, e); -+ t = get_transfer_for_easy(e); -+ if(t) { -+ t->done = 1; -+ fprintf(stderr, "[t-%d] FINISHED\n", t->idx); -+ if(use_earlydata) { -+ curl_off_t sent; -+ curl_easy_getinfo(e, CURLINFO_EARLYDATA_SENT_T, &sent); -+ fprintf(stderr, "[t-%d] EarlyData: %ld\n", t->idx, (long)sent); -+ } -+ } -+ else { -+ curl_easy_cleanup(e); -+ fprintf(stderr, "unknown FINISHED???\n"); -+ } -+ } -+ -+ -+ /* nothing happening, maintenance */ -+ if(abort_paused) { -+ /* abort paused transfers */ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->done && t->paused && t->easy) { -+ curl_multi_remove_handle(multi_handle, t->easy); -+ t->done = 1; -+ active_transfers--; -+ fprintf(stderr, "[t-%d] ABORTED\n", t->idx); -+ } -+ } -+ } -+ else { -+ /* resume one paused transfer */ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->done && t->paused) { -+ t->resumed = 1; -+ t->paused = 0; -+ curl_easy_pause(t->easy, CURLPAUSE_CONT); -+ fprintf(stderr, "[t-%d] RESUMED\n", t->idx); -+ break; -+ } -+ } -+ } -+ -+ while(active_transfers < max_parallel) { -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(!t->started) { -+ t->easy = curl_easy_init(); -+ if(!t->easy || setup(t->easy, url, t, http_version, host, -+ share, use_earlydata, announce_length)) { -+ fprintf(stderr, "[t-%d] FAILED setup\n", (int)i); -+ return 1; -+ } -+ curl_multi_add_handle(multi_handle, t->easy); -+ t->started = 1; -+ ++active_transfers; -+ fprintf(stderr, "[t-%d] STARTED\n", t->idx); -+ break; -+ } -+ } -+ /* all started */ -+ if(i == transfer_count) -+ break; -+ } -+ } while(m); -+ -+ } while(active_transfers); /* as long as we have transfers going */ -+ -+ curl_multi_cleanup(multi_handle); -+ } -+ -+ for(i = 0; i < transfer_count; ++i) { -+ t = &transfers[i]; -+ if(t->out) { -+ fclose(t->out); -+ t->out = NULL; -+ } -+ if(t->easy) { -+ curl_easy_cleanup(t->easy); -+ t->easy = NULL; -+ } -+ } -+ free(transfers); -+ curl_share_cleanup(share); -+ -+ return 0; -+#else -+ (void)argc; -+ (void)argv; -+ fprintf(stderr, "Not supported with this compiler.\n"); -+ return 1; -+#endif /* !_MSC_VER */ -+} -diff --git a/tests/http/clients/tls-session-reuse.c b/tests/http/clients/tls-session-reuse.c -index 0309276cf..8e8d63559 100644 ---- a/tests/http/clients/tls-session-reuse.c -+++ b/tests/http/clients/tls-session-reuse.c -@@ -25,16 +25,13 @@ - * TLS session reuse - * - */ -+#include -+ - #include - #include --#include - #include --#include - /* #include */ - #include --#include --#include -- - - static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) - { -@@ -73,8 +70,8 @@ static int debug_cb(CURL *handle, curl_infotype type, - if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { - if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && - conn_id >= 0) { -- curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, -- xfer_id, conn_id); -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); - } - else { - curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -@@ -142,7 +139,8 @@ static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *opaque) - } - - static void add_transfer(CURLM *multi, CURLSH *share, -- struct curl_slist *resolve, const char *url) -+ struct curl_slist *resolve, -+ const char *url, int http_version) - { - CURL *easy; - CURLMcode mc; -@@ -159,7 +157,7 @@ static void add_transfer(CURLM *multi, CURLSH *share, - curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1L); - curl_easy_setopt(easy, CURLOPT_AUTOREFERER, 1L); - curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L); -- curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); -+ curl_easy_setopt(easy, CURLOPT_HTTP_VERSION, http_version); - curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb); - curl_easy_setopt(easy, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L); -@@ -190,13 +188,19 @@ int main(int argc, char *argv[]) - int msgs_in_queue; - int add_more, waits, ongoing = 0; - char *host, *port; -+ int http_version = CURL_HTTP_VERSION_1_1; - -- if(argc != 2) { -- fprintf(stderr, "%s URL\n", argv[0]); -+ if(argc != 3) { -+ fprintf(stderr, "%s proto URL\n", argv[0]); - exit(2); - } - -- url = argv[1]; -+ if(!strcmp("h2", argv[1])) -+ http_version = CURL_HTTP_VERSION_2; -+ else if(!strcmp("h3", argv[1])) -+ http_version = CURL_HTTP_VERSION_3ONLY; -+ -+ url = argv[2]; - cu = curl_url(); - if(!cu) { - fprintf(stderr, "out of memory\n"); -@@ -215,9 +219,9 @@ int main(int argc, char *argv[]) - exit(1); - } - -- memset(&resolve, 0, sizeof(resolve)); -- curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, -- "%s:%s:127.0.0.1", host, port); -+ memset(&resolve, 0, sizeof(resolve)); -+ curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1", -+ host, port); - curl_slist_append(&resolve, resolve_buf); - - multi = curl_multi_init(); -@@ -234,7 +238,7 @@ int main(int argc, char *argv[]) - curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); - - -- add_transfer(multi, share, &resolve, url); -+ add_transfer(multi, share, &resolve, url, http_version); - ++ongoing; - add_more = 6; - waits = 3; -@@ -260,14 +264,15 @@ int main(int argc, char *argv[]) - } - else { - while(add_more) { -- add_transfer(multi, share, &resolve, url); -+ add_transfer(multi, share, &resolve, url, http_version); - ++ongoing; - --add_more; - } - } - - /* Check for finished handles and remove. */ -- while((msg = curl_multi_info_read(multi, &msgs_in_queue))) { -+ /* !checksrc! disable EQUALSNULL 1 */ -+ while((msg = curl_multi_info_read(multi, &msgs_in_queue)) != NULL) { - if(msg->msg == CURLMSG_DONE) { - long status = 0; - curl_off_t xfer_id; -diff --git a/tests/http/clients/upload-pausing.c b/tests/http/clients/upload-pausing.c -new file mode 100644 -index 000000000..ff68b7bd1 ---- /dev/null -+++ b/tests/http/clients/upload-pausing.c -@@ -0,0 +1,321 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+/* -+ * upload pausing -+ * -+ */ -+/* This is based on the PoC client of issue #11769 -+ */ -+#include -+ -+#include -+#include -+#include -+ -+#ifndef _MSC_VER -+/* somewhat Unix-specific */ -+#include /* getopt() */ -+#endif -+ -+#ifndef _MSC_VER -+static void log_line_start(FILE *log, const char *idsbuf, curl_infotype type) -+{ -+ /* -+ * This is the trace look that is similar to what libcurl makes on its -+ * own. -+ */ -+ static const char * const s_infotype[] = { -+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " -+ }; -+ if(idsbuf && *idsbuf) -+ fprintf(log, "%s%s", idsbuf, s_infotype[type]); -+ else -+ fputs(s_infotype[type], log); -+} -+ -+#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] " -+#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \ -+ CURL_FORMAT_CURL_OFF_T "] " -+/* -+** callback for CURLOPT_DEBUGFUNCTION -+*/ -+static int debug_cb(CURL *handle, curl_infotype type, -+ char *data, size_t size, -+ void *userdata) -+{ -+ FILE *output = stderr; -+ static int newl = 0; -+ static int traced_data = 0; -+ char idsbuf[60]; -+ curl_off_t xfer_id, conn_id; -+ -+ (void)handle; /* not used */ -+ (void)userdata; -+ -+ if(!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) { -+ if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) && -+ conn_id >= 0) { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2, xfer_id, -+ conn_id); -+ } -+ else { -+ curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id); -+ } -+ } -+ else -+ idsbuf[0] = 0; -+ -+ switch(type) { -+ case CURLINFO_HEADER_OUT: -+ if(size > 0) { -+ size_t st = 0; -+ size_t i; -+ for(i = 0; i < size - 1; i++) { -+ if(data[i] == '\n') { /* LF */ -+ if(!newl) { -+ log_line_start(output, idsbuf, type); -+ } -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ st = i + 1; -+ newl = 0; -+ } -+ } -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data + st, i - st + 1, 1, output); -+ } -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_TEXT: -+ case CURLINFO_HEADER_IN: -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ (void)fwrite(data, size, 1, output); -+ newl = (size && (data[size - 1] != '\n')) ? 1 : 0; -+ traced_data = 0; -+ break; -+ case CURLINFO_DATA_OUT: -+ case CURLINFO_DATA_IN: -+ case CURLINFO_SSL_DATA_IN: -+ case CURLINFO_SSL_DATA_OUT: -+ if(!traced_data) { -+ if(!newl) -+ log_line_start(output, idsbuf, type); -+ fprintf(output, "[%ld bytes data]\n", (long)size); -+ newl = 0; -+ traced_data = 1; -+ } -+ break; -+ default: /* nada */ -+ newl = 0; -+ traced_data = 1; -+ break; -+ } -+ -+ return 0; -+} -+ -+#define PAUSE_READ_AFTER 1 -+static size_t total_read = 0; -+ -+static size_t read_callback(char *ptr, size_t size, size_t nmemb, -+ void *userdata) -+{ -+ (void)size; -+ (void)nmemb; -+ (void)userdata; -+ if(total_read >= PAUSE_READ_AFTER) { -+ fprintf(stderr, "read_callback, return PAUSE\n"); -+ return CURL_READFUNC_PAUSE; -+ } -+ else { -+ ptr[0] = '\n'; -+ ++total_read; -+ fprintf(stderr, "read_callback, return 1 byte\n"); -+ return 1; -+ } -+} -+ -+static int progress_callback(void *clientp, -+ curl_off_t dltotal, -+ curl_off_t dlnow, -+ curl_off_t ultotal, -+ curl_off_t ulnow) -+{ -+ (void)dltotal; -+ (void)dlnow; -+ (void)ultotal; -+ (void)ulnow; -+ (void)clientp; -+#if 0 -+ /* Used to unpause on progress, but keeping for now. */ -+ { -+ CURL *curl = (CURL *)clientp; -+ curl_easy_pause(curl, CURLPAUSE_CONT); -+ /* curl_easy_pause(curl, CURLPAUSE_RECV_CONT); */ -+ } -+#endif -+ return 0; -+} -+ -+static int err(void) -+{ -+ fprintf(stderr, "something unexpected went wrong - bailing out!\n"); -+ exit(2); -+} -+ -+static void usage(const char *msg) -+{ -+ if(msg) -+ fprintf(stderr, "%s\n", msg); -+ fprintf(stderr, -+ "usage: [options] url\n" -+ " upload and pause, options:\n" -+ " -V http_version (http/1.1, h2, h3) http version to use\n" -+ ); -+} -+#endif /* !_MSC_VER */ -+ -+int main(int argc, char *argv[]) -+{ -+#ifndef _MSC_VER -+ CURL *curl; -+ CURLcode rc = CURLE_OK; -+ CURLU *cu; -+ struct curl_slist *resolve = NULL; -+ char resolve_buf[1024]; -+ char *url, *host = NULL, *port = NULL; -+ int http_version = CURL_HTTP_VERSION_1_1; -+ int ch; -+ -+ while((ch = getopt(argc, argv, "V:")) != -1) { -+ switch(ch) { -+ case 'V': { -+ if(!strcmp("http/1.1", optarg)) -+ http_version = CURL_HTTP_VERSION_1_1; -+ else if(!strcmp("h2", optarg)) -+ http_version = CURL_HTTP_VERSION_2_0; -+ else if(!strcmp("h3", optarg)) -+ http_version = CURL_HTTP_VERSION_3ONLY; -+ else { -+ usage("invalid http version"); -+ return 1; -+ } -+ break; -+ } -+ default: -+ usage("invalid option"); -+ return 1; -+ } -+ } -+ argc -= optind; -+ argv += optind; -+ -+ if(argc != 1) { -+ usage("not enough arguments"); -+ return 2; -+ } -+ url = argv[0]; -+ -+ curl_global_init(CURL_GLOBAL_DEFAULT); -+ curl_global_trace("ids,time"); -+ -+ cu = curl_url(); -+ if(!cu) { -+ fprintf(stderr, "out of memory\n"); -+ exit(1); -+ } -+ if(curl_url_set(cu, CURLUPART_URL, url, 0)) { -+ fprintf(stderr, "not a URL: '%s'\n", url); -+ exit(1); -+ } -+ if(curl_url_get(cu, CURLUPART_HOST, &host, 0)) { -+ fprintf(stderr, "could not get host of '%s'\n", url); -+ exit(1); -+ } -+ if(curl_url_get(cu, CURLUPART_PORT, &port, 0)) { -+ fprintf(stderr, "could not get port of '%s'\n", url); -+ exit(1); -+ } -+ memset(&resolve, 0, sizeof(resolve)); -+ curl_msnprintf(resolve_buf, sizeof(resolve_buf)-1, "%s:%s:127.0.0.1", -+ host, port); -+ resolve = curl_slist_append(resolve, resolve_buf); -+ -+ curl = curl_easy_init(); -+ if(!curl) { -+ fprintf(stderr, "out of memory\n"); -+ exit(1); -+ } -+ /* We want to use our own read function. */ -+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); -+ -+ /* It will help us to continue the read function. */ -+ curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); -+ curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl); -+ curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); -+ -+ /* It will help us to ensure that keepalive does not help. */ -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L); -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L); -+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 1L); -+ -+ /* Enable uploading. */ -+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); -+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); -+ -+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); -+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); -+ -+ if(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) != CURLE_OK || -+ curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_cb) -+ != CURLE_OK || -+ curl_easy_setopt(curl, CURLOPT_RESOLVE, resolve) != CURLE_OK) -+ err(); -+ -+ curl_easy_setopt(curl, CURLOPT_URL, url); -+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, http_version); -+ -+ rc = curl_easy_perform(curl); -+ -+ if(curl) { -+ curl_easy_cleanup(curl); -+ } -+ -+ curl_slist_free_all(resolve); -+ curl_free(host); -+ curl_free(port); -+ curl_url_cleanup(cu); -+ curl_global_cleanup(); -+ -+ return (int)rc; -+#else -+ (void)argc; -+ (void)argv; -+ fprintf(stderr, "Not supported with this compiler.\n"); -+ return 1; -+#endif /* !_MSC_VER */ -+} -diff --git a/tests/http/clients/ws-data.c b/tests/http/clients/ws-data.c -index 487d109ef..6698326df 100644 ---- a/tests/http/clients/ws-data.c -+++ b/tests/http/clients/ws-data.c -@@ -22,10 +22,9 @@ - * - ***************************************************************************/ - /* -- * Websockets data echos -+ * WebSockets data echos - * - */ -- - /* curl stuff */ - #include "curl_setup.h" - #include -@@ -34,11 +33,16 @@ - #include - #include - --/* somewhat unix-specific */ --#include --#include -+#ifndef CURL_DISABLE_WEBSOCKETS - --#ifdef USE_WEBSOCKETS -+#ifdef _WIN32 -+#ifndef WIN32_LEAN_AND_MEAN -+#define WIN32_LEAN_AND_MEAN -+#endif -+#include -+#else -+#include -+#endif - - static - void dump(const char *text, unsigned char *ptr, size_t size, -@@ -56,7 +60,7 @@ void dump(const char *text, unsigned char *ptr, size_t size, - fprintf(stderr, "%s, %lu bytes (0x%lx)\n", - text, (unsigned long)size, (unsigned long)size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -112,7 +116,11 @@ static CURLcode recv_binary(CURL *curl, char *exp_data, size_t exp_len) - result = curl_ws_recv(curl, recvbuf, sizeof(recvbuf), &nread, &frame); - if(result == CURLE_AGAIN) { - fprintf(stderr, "EAGAIN, sleep, try again\n"); -+#ifdef _WIN32 -+ Sleep(100); -+#else - usleep(100*1000); -+#endif - continue; - } - fprintf(stderr, "ws: curl_ws_recv(offset=%ld, len=%ld) -> %d, %ld\n", -@@ -168,7 +176,7 @@ static void websocket_close(CURL *curl) - - static CURLcode data_echo(CURL *curl, size_t plen_min, size_t plen_max) - { -- CURLcode res; -+ CURLcode res = CURLE_OK; - size_t len; - char *send_buf; - size_t i; -@@ -202,7 +210,7 @@ out: - - int main(int argc, char *argv[]) - { --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - CURL *curl; - CURLcode res = CURLE_OK; - const char *url; -@@ -254,10 +262,10 @@ int main(int argc, char *argv[]) - curl_global_cleanup(); - return (int)res; - --#else /* USE_WEBSOCKETS */ -+#else /* !CURL_DISABLE_WEBSOCKETS */ - (void)argc; - (void)argv; -- fprintf(stderr, "websockets not enabled in libcurl\n"); -+ fprintf(stderr, "WebSockets not enabled in libcurl\n"); - return 1; --#endif /* !USE_WEBSOCKETS */ -+#endif /* CURL_DISABLE_WEBSOCKETS */ - } -diff --git a/tests/http/clients/ws-pingpong.c b/tests/http/clients/ws-pingpong.c -index dc36d4548..efb01bcd7 100644 ---- a/tests/http/clients/ws-pingpong.c -+++ b/tests/http/clients/ws-pingpong.c -@@ -22,10 +22,9 @@ - * - ***************************************************************************/ - /* -- * Websockets pingpong -+ * WebSockets pingpong - * - */ -- - /* curl stuff */ - #include "curl_setup.h" - #include -@@ -34,11 +33,16 @@ - #include - #include - --/* somewhat unix-specific */ -+#ifdef _WIN32 -+#ifndef WIN32_LEAN_AND_MEAN -+#define WIN32_LEAN_AND_MEAN -+#endif -+#include -+#else - #include --#include -+#endif - --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - - static CURLcode ping(CURL *curl, const char *send_payload) - { -@@ -102,7 +106,11 @@ static CURLcode pingpong(CURL *curl, const char *payload) - fprintf(stderr, "Receive pong\n"); - res = recv_pong(curl, payload); - if(res == CURLE_AGAIN) { -+#ifdef _WIN32 -+ Sleep(100); -+#else - usleep(100*1000); -+#endif - continue; - } - websocket_close(curl); -@@ -116,7 +124,7 @@ static CURLcode pingpong(CURL *curl, const char *payload) - - int main(int argc, char *argv[]) - { --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - CURL *curl; - CURLcode res = CURLE_OK; - const char *url, *payload; -@@ -149,10 +157,10 @@ int main(int argc, char *argv[]) - curl_global_cleanup(); - return (int)res; - --#else /* USE_WEBSOCKETS */ -+#else /* !CURL_DISABLE_WEBSOCKETS */ - (void)argc; - (void)argv; -- fprintf(stderr, "websockets not enabled in libcurl\n"); -+ fprintf(stderr, "WebSockets not enabled in libcurl\n"); - return 1; --#endif /* !USE_WEBSOCKETS */ -+#endif /* CURL_DISABLE_WEBSOCKETS */ - } -diff --git a/tests/http/config.ini.in b/tests/http/config.ini.in -index 42a967906..8475c03b8 100644 ---- a/tests/http/config.ini.in -+++ b/tests/http/config.ini.in -@@ -35,3 +35,6 @@ nghttpx = @HTTPD_NGHTTPX@ - - [caddy] - caddy = @CADDY@ -+ -+[vsftpd] -+vsftpd = @VSFTPD@ -diff --git a/tests/http/conftest.py b/tests/http/conftest.py -index 3aca42e66..b29cf38bb 100644 ---- a/tests/http/conftest.py -+++ b/tests/http/conftest.py -@@ -25,7 +25,8 @@ - import logging - import os - import sys --from typing import Optional -+import platform -+from typing import Generator - - import pytest - -@@ -33,6 +34,44 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '.')) - - from testenv import Env, Nghttpx, Httpd, NghttpxQuic, NghttpxFwd - -+def pytest_report_header(config): -+ # Env inits its base properties only once, we can report them here -+ env = Env() -+ report = [ -+ f'Testing curl {env.curl_version()}', -+ f' platform: {platform.platform()}', -+ f' curl: Version: {env.curl_version_string()}', -+ f' curl: Features: {env.curl_features_string()}', -+ f' curl: Protocols: {env.curl_protocols_string()}', -+ f' httpd: {env.httpd_version()}, http:{env.http_port} https:{env.https_port}', -+ f' httpd-proxy: {env.httpd_version()}, http:{env.proxy_port} https:{env.proxys_port}' -+ ] -+ if env.have_h3(): -+ report.extend([ -+ f' nghttpx: {env.nghttpx_version()}, h3:{env.https_port}' -+ ]) -+ if env.has_caddy(): -+ report.extend([ -+ f' Caddy: {env.caddy_version()}, http:{env.caddy_http_port} https:{env.caddy_https_port}' -+ ]) -+ if env.has_vsftpd(): -+ report.extend([ -+ f' VsFTPD: {env.vsftpd_version()}, ftp:{env.ftp_port}, ftps:{env.ftps_port}' -+ ]) -+ buildinfo_fn = os.path.join(env.build_dir, 'buildinfo.txt') -+ if os.path.exists(buildinfo_fn): -+ with open(buildinfo_fn, 'r') as file_in: -+ for line in file_in: -+ line = line.strip() -+ if line and not line.startswith('#'): -+ report.extend([line]) -+ return '\n'.join(report) -+ -+# TODO: remove this and repeat argument everywhere, pytest-repeat can be used to repeat tests -+def pytest_generate_tests(metafunc): -+ if "repeat" in metafunc.fixturenames: -+ metafunc.parametrize('repeat', [0]) -+ - @pytest.fixture(scope="package") - def env(pytestconfig) -> Env: - env = Env(pytestconfig=pytestconfig) -@@ -46,8 +85,6 @@ def env(pytestconfig) -> Env: - pytest.skip(env.incomplete_reason()) - - env.setup() -- if not env.make_clients(): -- pytest.exit(1) - return env - - @pytest.fixture(scope="package", autouse=True) -@@ -56,7 +93,7 @@ def log_global_env_facts(record_testsuite_property, env): - - - @pytest.fixture(scope='package') --def httpd(env) -> Httpd: -+def httpd(env) -> Generator[Httpd, None, None]: - httpd = Httpd(env=env) - if not httpd.exists(): - pytest.skip(f'httpd not found: {env.httpd}') -@@ -68,18 +105,18 @@ def httpd(env) -> Httpd: - - - @pytest.fixture(scope='package') --def nghttpx(env, httpd) -> Optional[Nghttpx]: -+def nghttpx(env, httpd) -> Generator[Nghttpx, None, None]: - nghttpx = NghttpxQuic(env=env) -- if env.have_h3(): -+ if nghttpx.exists() and (env.have_h3() or nghttpx.https_port > 0): - nghttpx.clear_logs() - assert nghttpx.start() - yield nghttpx - nghttpx.stop() - - @pytest.fixture(scope='package') --def nghttpx_fwd(env, httpd) -> Optional[Nghttpx]: -+def nghttpx_fwd(env, httpd) -> Generator[Nghttpx, None, None]: - nghttpx = NghttpxFwd(env=env) -- if env.have_h3(): -+ if nghttpx.exists() and (env.have_h3() or nghttpx.https_port > 0): - nghttpx.clear_logs() - assert nghttpx.start() - yield nghttpx -diff --git a/tests/http/scorecard.py b/tests/http/scorecard.py -index 446a1bc5c..c675d9c5e 100644 ---- a/tests/http/scorecard.py -+++ b/tests/http/scorecard.py -@@ -33,39 +33,43 @@ import sys - from statistics import mean - from typing import Dict, Any, Optional, List - --from testenv import Env, Httpd, Nghttpx, CurlClient, Caddy, ExecResult, NghttpxQuic, RunProfile -+from testenv import Env, Httpd, CurlClient, Caddy, ExecResult, NghttpxQuic, RunProfile - - log = logging.getLogger(__name__) - - --class ScoreCardException(Exception): -+class ScoreCardError(Exception): - pass - - - class ScoreCard: - - def __init__(self, env: Env, -- httpd: Optional[Httpd], -- nghttpx: Optional[Nghttpx], -- caddy: Optional[Caddy], -+ protocol: str, -+ server_descr: str, -+ server_port: int, - verbose: int, -- curl_verbose: int): -+ curl_verbose: int, -+ download_parallel: int = 0, -+ server_addr: Optional[str] = None): - self.verbose = verbose - self.env = env -- self.httpd = httpd -- self.nghttpx = nghttpx -- self.caddy = caddy -+ self.protocol = protocol -+ self.server_descr = server_descr -+ self.server_addr = server_addr -+ self.server_port = server_port - self._silent_curl = not curl_verbose -+ self._download_parallel = download_parallel - - def info(self, msg): - if self.verbose > 0: - sys.stderr.write(msg) - sys.stderr.flush() - -- def handshakes(self, proto: str) -> Dict[str, Any]: -+ def handshakes(self) -> Dict[str, Any]: - props = {} - sample_size = 5 -- self.info(f'TLS Handshake\n') -+ self.info('TLS Handshake\n') - for authority in [ - 'curl.se', 'google.com', 'cloudflare.com', 'nghttp2.org' - ]: -@@ -76,10 +80,11 @@ class ScoreCard: - c_samples = [] - hs_samples = [] - errors = [] -- for i in range(sample_size): -- curl = CurlClient(env=self.env, silent=self._silent_curl) -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) - args = [ -- '--http3-only' if proto == 'h3' else '--http2', -+ '--http3-only' if self.protocol == 'h3' else '--http2', - f'--{ipv}', f'https://{authority}/' - ] - r = curl.run_direct(args=args, with_stats=True) -@@ -104,7 +109,17 @@ class ScoreCard: - while flen < fsize: - fd.write(data1k) - flen += len(data1k) -- return flen -+ return fpath -+ -+ def setup_resources(self, server_docs: str, -+ downloads: Optional[List[int]] = None): -+ for fsize in downloads: -+ label = self.fmt_size(fsize) -+ fname = f'score{label}.data' -+ self._make_docs_file(docs_dir=server_docs, -+ fname=fname, fsize=fsize) -+ self._make_docs_file(docs_dir=server_docs, -+ fname='reqs10.data', fsize=10*1024) - - def _check_downloads(self, r: ExecResult, count: int): - error = '' -@@ -117,17 +132,19 @@ class ScoreCard: - error += f'{len(fails)} failed' - return error if len(error) > 0 else None - -- def transfer_single(self, url: str, proto: str, count: int): -+ def transfer_single(self, url: str, count: int): - sample_size = count - count = 1 - samples = [] - errors = [] - profiles = [] -- self.info(f'single...') -- for i in range(sample_size): -- curl = CurlClient(env=self.env, silent=self._silent_curl) -- r = curl.http_download(urls=[url], alpn_proto=proto, no_save=True, -- with_headers=False, with_profile=True) -+ self.info('single...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_download(urls=[url], alpn_proto=self.protocol, -+ no_save=True, with_headers=False, -+ with_profile=True) - err = self._check_downloads(r, count) - if err: - errors.append(err) -@@ -138,21 +155,24 @@ class ScoreCard: - return { - 'count': count, - 'samples': sample_size, -+ 'max-parallel': 1, - 'speed': mean(samples) if len(samples) else -1, - 'errors': errors, - 'stats': RunProfile.AverageStats(profiles), - } - -- def transfer_serial(self, url: str, proto: str, count: int): -+ def transfer_serial(self, url: str, count: int): - sample_size = 1 - samples = [] - errors = [] - profiles = [] - url = f'{url}?[0-{count - 1}]' -- self.info(f'serial...') -- for i in range(sample_size): -- curl = CurlClient(env=self.env, silent=self._silent_curl) -- r = curl.http_download(urls=[url], alpn_proto=proto, no_save=True, -+ self.info('serial...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_download(urls=[url], alpn_proto=self.protocol, -+ no_save=True, - with_headers=False, with_profile=True) - err = self._check_downloads(r, count) - if err: -@@ -164,25 +184,31 @@ class ScoreCard: - return { - 'count': count, - 'samples': sample_size, -+ 'max-parallel': 1, - 'speed': mean(samples) if len(samples) else -1, - 'errors': errors, - 'stats': RunProfile.AverageStats(profiles), - } - -- def transfer_parallel(self, url: str, proto: str, count: int): -+ def transfer_parallel(self, url: str, count: int): - sample_size = 1 - samples = [] - errors = [] - profiles = [] -+ max_parallel = self._download_parallel if self._download_parallel > 0 else count - url = f'{url}?[0-{count - 1}]' -- self.info(f'parallel...') -- for i in range(sample_size): -- curl = CurlClient(env=self.env, silent=self._silent_curl) -- r = curl.http_download(urls=[url], alpn_proto=proto, no_save=True, -+ self.info('parallel...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_download(urls=[url], alpn_proto=self.protocol, -+ no_save=True, - with_headers=False, - with_profile=True, -- extra_args=['--parallel', -- '--parallel-max', str(count)]) -+ extra_args=[ -+ '--parallel', -+ '--parallel-max', str(max_parallel) -+ ]) - err = self._check_downloads(r, count) - if err: - errors.append(err) -@@ -193,198 +219,269 @@ class ScoreCard: - return { - 'count': count, - 'samples': sample_size, -+ 'max-parallel': max_parallel, - 'speed': mean(samples) if len(samples) else -1, - 'errors': errors, - 'stats': RunProfile.AverageStats(profiles), - } - -- def download_url(self, label: str, url: str, proto: str, count: int): -+ def download_url(self, label: str, url: str, count: int): - self.info(f' {count}x{label}: ') - props = { -- 'single': self.transfer_single(url=url, proto=proto, count=10), -+ 'single': self.transfer_single(url=url, count=10), - } - if count > 1: -- props['serial'] = self.transfer_serial(url=url, proto=proto, -- count=count) -- props['parallel'] = self.transfer_parallel(url=url, proto=proto, -- count=count) -- self.info(f'ok.\n') -+ props['serial'] = self.transfer_serial(url=url, count=count) -+ props['parallel'] = self.transfer_parallel(url=url, count=count) -+ self.info('ok.\n') - return props - -- def downloads(self, proto: str, count: int, -- fsizes: List[int]) -> Dict[str, Any]: -+ def downloads(self, count: int, fsizes: List[int]) -> Dict[str, Any]: - scores = {} -- if self.httpd: -- if proto == 'h3': -- port = self.env.h3_port -- via = 'nghttpx' -- descr = f'port {port}, proxying httpd' -- else: -- port = self.env.https_port -- via = 'httpd' -- descr = f'port {port}' -- self.info(f'{via} downloads\n') -- scores[via] = { -- 'description': descr, -- } -- for fsize in fsizes: -- label = self.fmt_size(fsize) -- fname = f'score{label}.data' -- self._make_docs_file(docs_dir=self.httpd.docs_dir, -- fname=fname, fsize=fsize) -- url = f'https://{self.env.domain1}:{port}/{fname}' -- results = self.download_url(label=label, url=url, -- proto=proto, count=count) -- scores[via][label] = results -- if self.caddy: -- port = self.caddy.port -- via = 'caddy' -- descr = f'port {port}' -- self.info('caddy downloads\n') -- scores[via] = { -- 'description': descr, -- } -- for fsize in fsizes: -- label = self.fmt_size(fsize) -- fname = f'score{label}.data' -- self._make_docs_file(docs_dir=self.caddy.docs_dir, -- fname=fname, fsize=fsize) -- url = f'https://{self.env.domain1}:{port}/{fname}' -- results = self.download_url(label=label, url=url, -- proto=proto, count=count) -- scores[via][label] = results -+ for fsize in fsizes: -+ label = self.fmt_size(fsize) -+ fname = f'score{label}.data' -+ url = f'https://{self.env.domain1}:{self.server_port}/{fname}' -+ scores[label] = self.download_url(label=label, url=url, count=count) - return scores - -- def do_requests(self, url: str, proto: str, count: int, -- max_parallel: int = 1): -+ def _check_uploads(self, r: ExecResult, count: int): -+ error = '' -+ if r.exit_code != 0: -+ error += f'exit={r.exit_code} ' -+ if r.exit_code != 0 or len(r.stats) != count: -+ error += f'stats={len(r.stats)}/{count} ' -+ fails = [s for s in r.stats if s['response_code'] != 200] -+ if len(fails) > 0: -+ error += f'{len(fails)} failed' -+ for f in fails: -+ error += f'[{f["response_code"]}]' -+ return error if len(error) > 0 else None -+ -+ def upload_single(self, url: str, fpath: str, count: int): -+ sample_size = count -+ count = 1 -+ samples = [] -+ errors = [] -+ profiles = [] -+ self.info('single...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=self.protocol, -+ with_headers=False, with_profile=True) -+ err = self._check_uploads(r, count) -+ if err: -+ errors.append(err) -+ else: -+ total_size = sum([s['size_upload'] for s in r.stats]) -+ samples.append(total_size / r.duration.total_seconds()) -+ profiles.append(r.profile) -+ return { -+ 'count': count, -+ 'samples': sample_size, -+ 'max-parallel': 1, -+ 'speed': mean(samples) if len(samples) else -1, -+ 'errors': errors, -+ 'stats': RunProfile.AverageStats(profiles) if len(profiles) else {}, -+ } -+ -+ def upload_serial(self, url: str, fpath: str, count: int): - sample_size = 1 - samples = [] - errors = [] - profiles = [] -- url = f'{url}?[0-{count - 1}]' -- extra_args = ['--parallel', '--parallel-max', str(max_parallel)] \ -- if max_parallel > 1 else [] -- self.info(f'{max_parallel}...') -- for i in range(sample_size): -- curl = CurlClient(env=self.env, silent=self._silent_curl) -- r = curl.http_download(urls=[url], alpn_proto=proto, no_save=True, -- with_headers=False, with_profile=True, -- extra_args=extra_args) -- err = self._check_downloads(r, count) -+ url = f'{url}?id=[0-{count - 1}]' -+ self.info('serial...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=self.protocol, -+ with_headers=False, with_profile=True) -+ err = self._check_uploads(r, count) - if err: - errors.append(err) - else: -- for _ in r.stats: -- samples.append(count / r.duration.total_seconds()) -+ total_size = sum([s['size_upload'] for s in r.stats]) -+ samples.append(total_size / r.duration.total_seconds()) - profiles.append(r.profile) - return { - 'count': count, - 'samples': sample_size, -+ 'max-parallel': 1, - 'speed': mean(samples) if len(samples) else -1, - 'errors': errors, -- 'stats': RunProfile.AverageStats(profiles), -+ 'stats': RunProfile.AverageStats(profiles) if len(profiles) else {}, - } - -- def requests_url(self, url: str, proto: str, count: int): -- self.info(f' {url}: ') -+ def upload_parallel(self, url: str, fpath: str, count: int): -+ sample_size = 1 -+ samples = [] -+ errors = [] -+ profiles = [] -+ max_parallel = count -+ url = f'{url}?id=[0-{count - 1}]' -+ self.info('parallel...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=self.protocol, -+ with_headers=False, with_profile=True, -+ extra_args=[ -+ '--parallel', -+ '--parallel-max', str(max_parallel) -+ ]) -+ err = self._check_uploads(r, count) -+ if err: -+ errors.append(err) -+ else: -+ total_size = sum([s['size_upload'] for s in r.stats]) -+ samples.append(total_size / r.duration.total_seconds()) -+ profiles.append(r.profile) -+ return { -+ 'count': count, -+ 'samples': sample_size, -+ 'max-parallel': max_parallel, -+ 'speed': mean(samples) if len(samples) else -1, -+ 'errors': errors, -+ 'stats': RunProfile.AverageStats(profiles) if len(profiles) else {}, -+ } -+ -+ def upload_url(self, label: str, url: str, fpath: str, count: int): -+ self.info(f' {count}x{label}: ') - props = { -- '1': self.do_requests(url=url, proto=proto, count=count), -- '6': self.do_requests(url=url, proto=proto, count=count, -- max_parallel=6), -- '25': self.do_requests(url=url, proto=proto, count=count, -- max_parallel=25), -- '50': self.do_requests(url=url, proto=proto, count=count, -- max_parallel=50), -- '100': self.do_requests(url=url, proto=proto, count=count, -- max_parallel=100), -+ 'single': self.upload_single(url=url, fpath=fpath, count=10), - } -- self.info(f'ok.\n') -+ if count > 1: -+ props['serial'] = self.upload_serial(url=url, fpath=fpath, count=count) -+ props['parallel'] = self.upload_parallel(url=url, fpath=fpath, count=count) -+ self.info('ok.\n') - return props - -- def requests(self, proto: str, req_count) -> Dict[str, Any]: -+ def uploads(self, count: int, fsizes: List[int]) -> Dict[str, Any]: - scores = {} -- if self.httpd: -- if proto == 'h3': -- port = self.env.h3_port -- via = 'nghttpx' -- descr = f'port {port}, proxying httpd' -- else: -- port = self.env.https_port -- via = 'httpd' -- descr = f'port {port}' -- self.info(f'{via} requests\n') -- self._make_docs_file(docs_dir=self.httpd.docs_dir, -- fname='reqs10.data', fsize=10*1024) -- url1 = f'https://{self.env.domain1}:{port}/reqs10.data' -- scores[via] = { -- 'description': descr, -- 'count': req_count, -- '10KB': self.requests_url(url=url1, proto=proto, count=req_count), -- } -- if self.caddy: -- port = self.caddy.port -- via = 'caddy' -- descr = f'port {port}' -- self.info('caddy requests\n') -- self._make_docs_file(docs_dir=self.caddy.docs_dir, -- fname='req10.data', fsize=10 * 1024) -- url1 = f'https://{self.env.domain1}:{port}/req10.data' -- scores[via] = { -- 'description': descr, -- 'count': req_count, -- '10KB': self.requests_url(url=url1, proto=proto, count=req_count), -- } -+ url = f'https://{self.env.domain2}:{self.server_port}/curltest/put' -+ fpaths = {} -+ for fsize in fsizes: -+ label = self.fmt_size(fsize) -+ fname = f'upload{label}.data' -+ fpaths[label] = self._make_docs_file(docs_dir=self.env.gen_dir, -+ fname=fname, fsize=fsize) -+ -+ for label, fpath in fpaths.items(): -+ scores[label] = self.upload_url(label=label, url=url, fpath=fpath, -+ count=count) - return scores - -- def score_proto(self, proto: str, -- handshakes: bool = True, -- downloads: Optional[List[int]] = None, -- download_count: int = 50, -- req_count=5000, -- requests: bool = True): -- self.info(f"scoring {proto}\n") -+ def do_requests(self, url: str, count: int, max_parallel: int = 1): -+ sample_size = 1 -+ samples = [] -+ errors = [] -+ profiles = [] -+ url = f'{url}?[0-{count - 1}]' -+ extra_args = [ -+ '-w', '%{response_code},\\n', -+ ] -+ if max_parallel > 1: -+ extra_args.extend([ -+ '--parallel', '--parallel-max', str(max_parallel) -+ ]) -+ self.info(f'{max_parallel}...') -+ for _ in range(sample_size): -+ curl = CurlClient(env=self.env, silent=self._silent_curl, -+ server_addr=self.server_addr) -+ r = curl.http_download(urls=[url], alpn_proto=self.protocol, no_save=True, -+ with_headers=False, with_profile=True, -+ with_stats=False, extra_args=extra_args) -+ if r.exit_code != 0: -+ errors.append(f'exit={r.exit_code}') -+ else: -+ samples.append(count / r.duration.total_seconds()) -+ non_200s = 0 -+ for line in r.stdout.splitlines(): -+ if not line.startswith('200,'): -+ non_200s += 1 -+ if non_200s > 0: -+ errors.append(f'responses != 200: {non_200s}') -+ profiles.append(r.profile) -+ return { -+ 'count': count, -+ 'samples': sample_size, -+ 'speed': mean(samples) if len(samples) else -1, -+ 'errors': errors, -+ 'stats': RunProfile.AverageStats(profiles), -+ } -+ -+ def requests_url(self, url: str, count: int): -+ self.info(f' {url}: ') -+ props = {} -+ # 300 is max in curl, see tool_main.h -+ for m in [1, 6, 25, 50, 100, 300]: -+ props[str(m)] = self.do_requests(url=url, count=count, max_parallel=m) -+ self.info('ok.\n') -+ return props -+ -+ def requests(self, req_count) -> Dict[str, Any]: -+ url = f'https://{self.env.domain1}:{self.server_port}/reqs10.data' -+ return { -+ 'count': req_count, -+ '10KB': self.requests_url(url=url, count=req_count), -+ } -+ -+ def score(self, -+ handshakes: bool = True, -+ downloads: Optional[List[int]] = None, -+ download_count: int = 50, -+ uploads: Optional[List[int]] = None, -+ upload_count: int = 50, -+ req_count=5000, -+ requests: bool = True): -+ self.info(f"scoring {self.protocol} against {self.server_descr}\n") - p = {} -- if proto == 'h3': -+ if self.protocol == 'h3': - p['name'] = 'h3' - if not self.env.have_h3_curl(): -- raise ScoreCardException('curl does not support HTTP/3') -+ raise ScoreCardError('curl does not support HTTP/3') - for lib in ['ngtcp2', 'quiche', 'msh3', 'nghttp3']: - if self.env.curl_uses_lib(lib): - p['implementation'] = lib - break -- elif proto == 'h2': -+ elif self.protocol == 'h2': - p['name'] = 'h2' - if not self.env.have_h2_curl(): -- raise ScoreCardException('curl does not support HTTP/2') -+ raise ScoreCardError('curl does not support HTTP/2') - for lib in ['nghttp2', 'hyper']: - if self.env.curl_uses_lib(lib): - p['implementation'] = lib - break -- elif proto == 'h1' or proto == 'http/1.1': -+ elif self.protocol == 'h1' or self.protocol == 'http/1.1': - proto = 'http/1.1' - p['name'] = proto - p['implementation'] = 'hyper' if self.env.curl_uses_lib('hyper')\ - else 'native' - else: -- raise ScoreCardException(f"unknown protocol: {proto}") -+ raise ScoreCardError(f"unknown protocol: {self.protocol}") - - if 'implementation' not in p: -- raise ScoreCardException(f'did not recognized {p} lib') -+ raise ScoreCardError(f'did not recognized {p} lib') - p['version'] = Env.curl_lib_version(p['implementation']) - - score = { - 'curl': self.env.curl_fullname(), - 'os': self.env.curl_os(), - 'protocol': p, -+ 'server': self.server_descr, - } - if handshakes: -- score['handshakes'] = self.handshakes(proto=proto) -+ score['handshakes'] = self.handshakes() - if downloads and len(downloads) > 0: -- score['downloads'] = self.downloads(proto=proto, -- count=download_count, -+ score['downloads'] = self.downloads(count=download_count, - fsizes=downloads) -+ if uploads and len(uploads) > 0: -+ score['uploads'] = self.uploads(count=upload_count, -+ fsizes=uploads) - if requests: -- score['requests'] = self.requests(proto=proto, req_count=req_count) -+ score['requests'] = self.requests(req_count=req_count) - self.info("\n") - return score - -@@ -427,42 +524,86 @@ class ScoreCard: - m_names = {} - mcol_width = 12 - mcol_sw = 17 -- for server, server_score in score['downloads'].items(): -- for sskey, ssval in server_score.items(): -- if isinstance(ssval, str): -- continue -- if sskey not in sizes: -- sizes.append(sskey) -- for mkey, mval in server_score[sskey].items(): -- if mkey not in measures: -- measures.append(mkey) -- m_names[mkey] = f'{mkey}({mval["count"]}x)' -- -- print('Downloads') -- print(f' {"Server":<8} {"Size":>8}', end='') -- for m in measures: print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='') -+ for sskey, ssval in score['downloads'].items(): -+ if isinstance(ssval, str): -+ continue -+ if sskey not in sizes: -+ sizes.append(sskey) -+ for mkey, mval in score['downloads'][sskey].items(): -+ if mkey not in measures: -+ measures.append(mkey) -+ m_names[mkey] = f'{mkey}({mval["count"]}x{mval["max-parallel"]})' -+ print(f'Downloads from {score["server"]}') -+ print(f' {"Size":>8}', end='') -+ for m in measures: -+ print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='') - print(f' {"Errors":^20}') - -- for server in score['downloads']: -- for size in sizes: -- size_score = score['downloads'][server][size] -- print(f' {server:<8} {size:>8}', end='') -- errors = [] -- for key, val in size_score.items(): -- if 'errors' in val: -- errors.extend(val['errors']) -- for m in measures: -- if m in size_score: -- print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='') -- s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\ -- f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]' -- print(f' {s:<{mcol_sw}}', end='') -+ for size in score['downloads']: -+ size_score = score['downloads'][size] -+ print(f' {size:>8}', end='') -+ errors = [] -+ for val in size_score.values(): -+ if 'errors' in val: -+ errors.extend(val['errors']) -+ for m in measures: -+ if m in size_score: -+ print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='') -+ s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\ -+ f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]' -+ print(f' {s:<{mcol_sw}}', end='') -+ else: -+ print(' '*mcol_width, end='') -+ if len(errors): -+ print(f' {"/".join(errors):<20}') -+ else: -+ print(f' {"-":^20}') -+ -+ if 'uploads' in score: -+ # get the key names of all sizes and measurements made -+ sizes = [] -+ measures = [] -+ m_names = {} -+ mcol_width = 12 -+ mcol_sw = 17 -+ for sskey, ssval in score['uploads'].items(): -+ if isinstance(ssval, str): -+ continue -+ if sskey not in sizes: -+ sizes.append(sskey) -+ for mkey, mval in ssval.items(): -+ if mkey not in measures: -+ measures.append(mkey) -+ m_names[mkey] = f'{mkey}({mval["count"]}x{mval["max-parallel"]})' -+ -+ print(f'Uploads to {score["server"]}') -+ print(f' {"Size":>8}', end='') -+ for m in measures: -+ print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='') -+ print(f' {"Errors":^20}') -+ -+ for size in sizes: -+ size_score = score['uploads'][size] -+ print(f' {size:>8}', end='') -+ errors = [] -+ for val in size_score.values(): -+ if 'errors' in val: -+ errors.extend(val['errors']) -+ for m in measures: -+ if m in size_score: -+ print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='') -+ stats = size_score[m]["stats"] -+ if 'cpu' in stats: -+ s = f'[{stats["cpu"]:>.1f}%/{self.fmt_size(stats["rss"])}]' - else: -- print(' '*mcol_width, end='') -- if len(errors): -- print(f' {"/".join(errors):<20}') -+ s = '[???/???]' -+ print(f' {s:<{mcol_sw}}', end='') - else: -- print(f' {"-":^20}') -+ print(' '*mcol_width, end='') -+ if len(errors): -+ print(f' {"/".join(errors):<20}') -+ else: -+ print(f' {"-":^20}') - - if 'requests' in score: - sizes = [] -@@ -470,44 +611,42 @@ class ScoreCard: - m_names = {} - mcol_width = 9 - mcol_sw = 13 -- for server in score['requests']: -- server_score = score['requests'][server] -- for sskey, ssval in server_score.items(): -- if isinstance(ssval, str) or isinstance(ssval, int): -- continue -- if sskey not in sizes: -- sizes.append(sskey) -- for mkey, mval in server_score[sskey].items(): -- if mkey not in measures: -- measures.append(mkey) -- m_names[mkey] = f'{mkey}' -- -- print('Requests, max in parallel') -- print(f' {"Server":<8} {"Size":>6} {"Reqs":>6}', end='') -- for m in measures: print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='') -+ for sskey, ssval in score['requests'].items(): -+ if isinstance(ssval, (str, int)): -+ continue -+ if sskey not in sizes: -+ sizes.append(sskey) -+ for mkey in score['requests'][sskey]: -+ if mkey not in measures: -+ measures.append(mkey) -+ m_names[mkey] = f'{mkey}' -+ -+ print('Requests (max parallel) to {score["server"]}') -+ print(f' {"Size":>6} {"Reqs":>6}', end='') -+ for m in measures: -+ print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='') - print(f' {"Errors":^10}') - -- for server in score['requests']: -- for size in sizes: -- size_score = score['requests'][server][size] -- count = score['requests'][server]['count'] -- print(f' {server:<8} {size:>6} {count:>6}', end='') -- errors = [] -- for key, val in size_score.items(): -- if 'errors' in val: -- errors.extend(val['errors']) -- for m in measures: -- if m in size_score: -- print(f' {self.fmt_reqs(size_score[m]["speed"]):>{mcol_width}}', end='') -- s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\ -- f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]' -- print(f' {s:<{mcol_sw}}', end='') -- else: -- print(' '*mcol_width, end='') -- if len(errors): -- print(f' {"/".join(errors):<10}') -+ for size in sizes: -+ size_score = score['requests'][size] -+ count = score['requests']['count'] -+ print(f' {size:>6} {count:>6}', end='') -+ errors = [] -+ for val in size_score.values(): -+ if 'errors' in val: -+ errors.extend(val['errors']) -+ for m in measures: -+ if m in size_score: -+ print(f' {self.fmt_reqs(size_score[m]["speed"]):>{mcol_width}}', end='') -+ s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\ -+ f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]' -+ print(f' {s:<{mcol_sw}}', end='') - else: -- print(f' {"-":^10}') -+ print(' '*mcol_width, end='') -+ if len(errors): -+ print(f' {"/".join(errors):<10}') -+ else: -+ print(f' {"-":^10}') - - - def parse_size(s): -@@ -543,6 +682,14 @@ def main(): - default=None, help="evaluate download size") - parser.add_argument("--download-count", action='store', type=int, - default=50, help="perform that many downloads") -+ parser.add_argument("--download-parallel", action='store', type=int, -+ default=0, help="perform that many downloads in parallel (default all)") -+ parser.add_argument("-u", "--uploads", action='store_true', -+ default=False, help="evaluate uploads") -+ parser.add_argument("--upload", action='append', type=str, -+ default=None, help="evaluate upload size") -+ parser.add_argument("--upload-count", action='store', type=int, -+ default=50, help="perform that many uploads") - parser.add_argument("-r", "--requests", action='store_true', - default=False, help="evaluate requests") - parser.add_argument("--request-count", action='store', type=int, -@@ -555,6 +702,10 @@ def main(): - default=False, help="run curl with `-v`") - parser.add_argument("protocol", default='h2', nargs='?', - help="Name of protocol to score") -+ parser.add_argument("--start-only", action='store_true', default=False, -+ help="only start the servers") -+ parser.add_argument("--remote", action='store', type=str, -+ default=None, help="score against the remote server at :") - args = parser.parse_args() - - if args.verbose > 0: -@@ -570,11 +721,20 @@ def main(): - downloads = [] - for x in args.download: - downloads.extend([parse_size(s) for s in x.split(',')]) -+ -+ uploads = [1024 * 1024, 10 * 1024 * 1024, 100 * 1024 * 1024] -+ if args.upload is not None: -+ uploads = [] -+ for x in args.upload: -+ uploads.extend([parse_size(s) for s in x.split(',')]) -+ - requests = True -- if args.downloads or args.requests or args.handshakes: -+ if args.downloads or args.uploads or args.requests or args.handshakes: - handshakes = args.handshakes - if not args.downloads: - downloads = None -+ if not args.uploads: -+ uploads = None - requests = args.requests - - test_httpd = protocol != 'h3' -@@ -591,36 +751,97 @@ def main(): - nghttpx = None - caddy = None - try: -+ cards = [] -+ -+ if args.remote: -+ m = re.match(r'^(.+):(\d+)$', args.remote) -+ if m is None: -+ raise ScoreCardError(f'unable to parse ip:port from --remote {args.remote}') -+ test_httpd = False -+ test_caddy = False -+ remote_addr = m.group(1) -+ remote_port = int(m.group(2)) -+ card = ScoreCard(env=env, -+ protocol=protocol, -+ server_descr=f'Server at {args.remote}', -+ server_addr=remote_addr, -+ server_port=remote_port, -+ verbose=args.verbose, curl_verbose=args.curl_verbose, -+ download_parallel=args.download_parallel) -+ cards.append(card) -+ - if test_httpd: - httpd = Httpd(env=env) - assert httpd.exists(), \ - f'httpd not found: {env.httpd}' - httpd.clear_logs() -+ server_docs = httpd.docs_dir - assert httpd.start() -- if 'h3' == protocol: -+ if protocol == 'h3': - nghttpx = NghttpxQuic(env=env) - nghttpx.clear_logs() - assert nghttpx.start() -+ server_descr = f'nghttpx: https:{env.h3_port} [backend httpd: {env.httpd_version()}, https:{env.https_port}]' -+ server_port = env.h3_port -+ else: -+ server_descr = f'httpd: {env.httpd_version()}, http:{env.http_port} https:{env.https_port}' -+ server_port = env.https_port -+ card = ScoreCard(env=env, -+ protocol=protocol, -+ server_descr=server_descr, -+ server_port=server_port, -+ verbose=args.verbose, curl_verbose=args.curl_verbose, -+ download_parallel=args.download_parallel) -+ card.setup_resources(server_docs, downloads) -+ cards.append(card) -+ - if test_caddy and env.caddy: -+ backend = '' -+ if uploads and httpd is None: -+ backend = f' [backend httpd: {env.httpd_version()}, http:{env.http_port} https:{env.https_port}]' -+ httpd = Httpd(env=env) -+ assert httpd.exists(), \ -+ f'httpd not found: {env.httpd}' -+ httpd.clear_logs() -+ assert httpd.start() - caddy = Caddy(env=env) - caddy.clear_logs() - assert caddy.start() -- -- card = ScoreCard(env=env, httpd=httpd, nghttpx=nghttpx, caddy=caddy, -- verbose=args.verbose, curl_verbose=args.curl_verbose) -- score = card.score_proto(proto=protocol, -- handshakes=handshakes, -- downloads=downloads, -- download_count=args.download_count, -- req_count=args.request_count, -- requests=requests) -- if args.json: -- print(json.JSONEncoder(indent=2).encode(score)) -+ server_descr = f'Caddy: {env.caddy_version()}, http:{env.caddy_http_port} https:{env.caddy_https_port}{backend}' -+ server_port = caddy.port -+ server_docs = caddy.docs_dir -+ card = ScoreCard(env=env, -+ protocol=protocol, -+ server_descr=server_descr, -+ server_port=server_port, -+ verbose=args.verbose, curl_verbose=args.curl_verbose, -+ download_parallel=args.download_parallel) -+ card.setup_resources(server_docs, downloads) -+ cards.append(card) -+ -+ if args.start_only: -+ print('started servers:') -+ for card in cards: -+ print(f'{card.server_descr}') -+ sys.stderr.write('press [RETURN] to finish') -+ sys.stderr.flush() -+ sys.stdin.readline() - else: -- card.print_score(score) -- -- except ScoreCardException as ex: -- sys.stderr.write(f"ERROR: {str(ex)}\n") -+ for card in cards: -+ score = card.score(handshakes=handshakes, -+ downloads=downloads, -+ download_count=args.download_count, -+ uploads=uploads, -+ upload_count=args.upload_count, -+ req_count=args.request_count, -+ requests=requests) -+ if args.json: -+ print(json.JSONEncoder(indent=2).encode(score)) -+ else: -+ card.print_score(score) -+ -+ except ScoreCardError as ex: -+ sys.stderr.write(f"ERROR: {ex}\n") - rv = 1 - except KeyboardInterrupt: - log.warning("aborted") -diff --git a/tests/http/test_01_basic.py b/tests/http/test_01_basic.py -index 3902b75b7..391c23151 100644 ---- a/tests/http/test_01_basic.py -+++ b/tests/http/test_01_basic.py -@@ -50,7 +50,7 @@ class TestBasic: - assert r.json['server'] == env.domain1 - - # simple https: GET, any http version -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - def test_01_02_https_get(self, env: Env, httpd): - curl = CurlClient(env=env) - url = f'https://{env.domain1}:{env.https_port}/data.json' -@@ -59,7 +59,7 @@ class TestBasic: - assert r.json['server'] == env.domain1 - - # simple https: GET, h2 wanted and got -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - def test_01_03_h2_get(self, env: Env, httpd): - curl = CurlClient(env=env) - url = f'https://{env.domain1}:{env.https_port}/data.json' -@@ -68,7 +68,7 @@ class TestBasic: - assert r.json['server'] == env.domain1 - - # simple https: GET, h2 unsupported, fallback to h1 -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - def test_01_04_h2_unsupported(self, env: Env, httpd): - curl = CurlClient(env=env) - url = f'https://{env.domain2}:{env.https_port}/data.json' -@@ -86,7 +86,7 @@ class TestBasic: - assert r.json['server'] == env.domain1 - - # simple download, check connect/handshake timings -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) - def test_01_06_timings(self, env: Env, httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): -@@ -94,8 +94,48 @@ class TestBasic: - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/data.json' - r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True) -- r.check_stats(http_status=200, count=1) -+ r.check_stats(http_status=200, count=1, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') - assert r.stats[0]['time_connect'] > 0, f'{r.stats[0]}' - assert r.stats[0]['time_appconnect'] > 0, f'{r.stats[0]}' - -+ # simple https: HEAD -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") -+ def test_01_07_head(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/data.json' -+ r = curl.http_download(urls=[url], with_stats=True, with_headers=True, -+ extra_args=['-I']) -+ r.check_stats(http_status=200, count=1, exitcode=0, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ # got the Conten-Length: header, but did not download anything -+ assert r.responses[0]['header']['content-length'] == '30', f'{r.responses[0]}' -+ assert r.stats[0]['size_download'] == 0, f'{r.stats[0]}' - -+ # http: GET for HTTP/2, see Upgrade:, 101 switch -+ def test_01_08_h2_upgrade(self, env: Env, httpd): -+ curl = CurlClient(env=env) -+ url = f'http://{env.domain1}:{env.http_port}/data.json' -+ r = curl.http_get(url=url, extra_args=['--http2']) -+ r.check_exit_code(0) -+ assert len(r.responses) == 2, f'{r.responses}' -+ assert r.responses[0]['status'] == 101, f'{r.responses[0]}' -+ assert r.responses[1]['status'] == 200, f'{r.responses[1]}' -+ assert r.responses[1]['protocol'] == 'HTTP/2', f'{r.responses[1]}' -+ assert r.json['server'] == env.domain1 -+ -+ # http: GET for HTTP/2 with prior knowledge -+ def test_01_09_h2_prior_knowledge(self, env: Env, httpd): -+ curl = CurlClient(env=env) -+ url = f'http://{env.domain1}:{env.http_port}/data.json' -+ r = curl.http_get(url=url, extra_args=['--http2-prior-knowledge']) -+ r.check_exit_code(0) -+ assert len(r.responses) == 1, f'{r.responses}' -+ assert r.response['status'] == 200, f'{r.responsw}' -+ assert r.response['protocol'] == 'HTTP/2', f'{r.response}' -+ assert r.json['server'] == env.domain1 -diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py -index 4db9c9d36..fe92df504 100644 ---- a/tests/http/test_02_download.py -+++ b/tests/http/test_02_download.py -@@ -27,7 +27,9 @@ - import difflib - import filecmp - import logging -+import math - import os -+import re - from datetime import timedelta - import pytest - -@@ -77,28 +79,30 @@ class TestDownload: - - # download 100 files sequentially - @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -- def test_02_03_download_100_sequential(self, env: Env, -- httpd, nghttpx, repeat, proto): -+ def test_02_03_download_sequential(self, env: Env, -+ httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -+ count = 10 - curl = CurlClient(env=env) -- urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-99]' -+ urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' - r = curl.http_download(urls=[urln], alpn_proto=proto) -- r.check_response(http_status=200, count=100, connect_count=1) -+ r.check_response(http_status=200, count=count, connect_count=1) - - # download 100 files parallel -- @pytest.mark.parametrize("proto", ['h2', 'h3']) -- def test_02_04_download_100_parallel(self, env: Env, -- httpd, nghttpx, repeat, proto): -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_04_download_parallel(self, env: Env, -+ httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- max_parallel = 50 -+ count = 10 -+ max_parallel = 5 - curl = CurlClient(env=env) -- urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-99]' -+ urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' - r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ - '--parallel', '--parallel-max', f'{max_parallel}' - ]) -- r.check_response(http_status=200, count=100) -+ r.check_response(http_status=200, count=count) - if proto == 'http/1.1': - # http/1.1 parallel transfers will open multiple connections - assert r.total_connects > 1, r.dump_logs() -@@ -164,8 +168,6 @@ class TestDownload: - @pytest.mark.parametrize("proto", ['http/1.1']) - def test_02_07b_download_reuse(self, env: Env, - httpd, nghttpx, repeat, proto): -- if env.curl_uses_lib('wolfssl'): -- pytest.skip("wolfssl session reuse borked") - count = 6 - curl = CurlClient(env=env) - urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' -@@ -182,7 +184,7 @@ class TestDownload: - httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- count = 20 -+ count = 5 - urln = f'https://{env.authority_for(env.domain1, proto)}/data-1m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto) -@@ -193,7 +195,7 @@ class TestDownload: - httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- count = 20 -+ count = 5 - urln = f'https://{env.authority_for(env.domain1, proto)}/data-1m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -@@ -208,7 +210,7 @@ class TestDownload: - httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- count = 10 -+ count = 3 - urln = f'https://{env.authority_for(env.domain1, proto)}/data-10m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto) -@@ -223,7 +225,7 @@ class TestDownload: - pytest.skip("h3 not supported") - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") -- count = 10 -+ count = 3 - urln = f'https://{env.authority_for(env.domain1, proto)}/data-10m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -@@ -236,7 +238,7 @@ class TestDownload: - httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- count = 50 -+ count = 5 - urln = f'https://{env.authority_for(env.domain1, proto)}/data-10m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -@@ -249,7 +251,7 @@ class TestDownload: - httpd, nghttpx, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") -- count = 50 -+ count = 5 - urln = f'http://{env.domain1}:{env.http_port}/data-10m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -@@ -257,8 +259,39 @@ class TestDownload: - ]) - r.check_response(count=count, http_status=200) - -+ @pytest.mark.parametrize("proto", ['h2', 'h3']) -+ def test_02_14_not_found(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 stalls here") -+ count = 5 -+ urln = f'https://{env.authority_for(env.domain1, proto)}/not-found?[0-{count-1}]' -+ curl = CurlClient(env=env) -+ r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_stats(count=count, http_status=404, exitcode=0, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ -+ @pytest.mark.parametrize("proto", ['h2', 'h3']) -+ def test_02_15_fail_not_found(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 stalls here") -+ count = 5 -+ urln = f'https://{env.authority_for(env.domain1, proto)}/not-found?[0-{count-1}]' -+ curl = CurlClient(env=env) -+ r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -+ '--fail' -+ ]) -+ r.check_stats(count=count, http_status=404, exitcode=22, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ - @pytest.mark.skipif(condition=Env().slow_network, reason="not suitable for slow network tests") -- @pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs") - def test_02_20_h2_small_frames(self, env: Env, httpd, repeat): - # Test case to reproduce content corruption as observed in - # https://github.com/curl/curl/issues/10525 -@@ -266,18 +299,18 @@ class TestDownload: - # setting smaller frame sizes. This is not released yet, we - # test if it works and back out if not. - httpd.set_extra_config(env.domain1, lines=[ -- f'H2MaxDataFrameLen 1024', -+ 'H2MaxDataFrameLen 1024', - ]) - assert httpd.stop() - if not httpd.start(): - # no, not supported, bail out - httpd.set_extra_config(env.domain1, lines=None) - assert httpd.start() -- pytest.skip(f'H2MaxDataFrameLen not supported') -+ pytest.skip('H2MaxDataFrameLen not supported') - # ok, make 100 downloads with 2 parallel running and they - # are expected to stumble into the issue when using `lib/http2.c` - # from curl 7.88.0 -- count = 100 -+ count = 5 - urln = f'https://{env.authority_for(env.domain1, "h2")}/data-1m?[0-{count-1}]' - curl = CurlClient(env=env) - r = curl.http_download(urls=[urln], alpn_proto="h2", extra_args=[ -@@ -293,15 +326,18 @@ class TestDownload: - - # download via lib client, 1 at a time, pause/resume at different offsets - @pytest.mark.parametrize("pause_offset", [0, 10*1024, 100*1023, 640000]) -- def test_02_21_h2_lib_serial(self, env: Env, httpd, nghttpx, pause_offset, repeat): -- count = 10 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_21_lib_serial(self, env: Env, httpd, nghttpx, proto, pause_offset, repeat): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 - docname = 'data-10m' - url = f'https://localhost:{env.https_port}/{docname}' -- client = LocalClient(name='h2-download', env=env) -+ client = LocalClient(name='hx-download', env=env) - if not client.exists(): - pytest.skip(f'example client not built: {client.name}') - r = client.run(args=[ -- '-n', f'{count}', '-P', f'{pause_offset}', url -+ '-n', f'{count}', '-P', f'{pause_offset}', '-V', proto, url - ]) - r.check_exit_code(0) - srcfile = os.path.join(httpd.docs_dir, docname) -@@ -309,35 +345,106 @@ class TestDownload: - - # download via lib client, several at a time, pause/resume - @pytest.mark.parametrize("pause_offset", [100*1023]) -- def test_02_22_h2_lib_parallel_resume(self, env: Env, httpd, nghttpx, pause_offset, repeat): -- count = 10 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_22_lib_parallel_resume(self, env: Env, httpd, nghttpx, proto, pause_offset, repeat): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 - max_parallel = 5 - docname = 'data-10m' - url = f'https://localhost:{env.https_port}/{docname}' -- client = LocalClient(name='h2-download', env=env) -+ client = LocalClient(name='hx-download', env=env) - if not client.exists(): - pytest.skip(f'example client not built: {client.name}') - r = client.run(args=[ - '-n', f'{count}', '-m', f'{max_parallel}', -- '-P', f'{pause_offset}', url -+ '-P', f'{pause_offset}', '-V', proto, url - ]) - r.check_exit_code(0) - srcfile = os.path.join(httpd.docs_dir, docname) - self.check_downloads(client, srcfile, count) - - # download, several at a time, pause and abort paused -- @pytest.mark.parametrize("pause_offset", [100*1023]) -- def test_02_23_h2_lib_parallel_abort(self, env: Env, httpd, nghttpx, pause_offset, repeat): -- count = 200 -- max_parallel = 100 -- docname = 'data-10m' -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_23a_lib_abort_paused(self, env: Env, httpd, nghttpx, proto, repeat): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_ossl_quic(): -+ pytest.skip('OpenSSL QUIC fails here') -+ if proto == 'h3' and env.ci_run and env.curl_uses_lib('quiche'): -+ pytest.skip("fails in CI, but works locally for unknown reasons") -+ count = 10 -+ max_parallel = 5 -+ if proto in ['h2', 'h3']: -+ pause_offset = 64 * 1024 -+ else: -+ pause_offset = 12 * 1024 -+ docname = 'data-1m' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-m', f'{max_parallel}', '-a', -+ '-P', f'{pause_offset}', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ srcfile = os.path.join(httpd.docs_dir, docname) -+ # downloads should be there, but not necessarily complete -+ self.check_downloads(client, srcfile, count, complete=False) -+ -+ # download, several at a time, abort after n bytes -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_23b_lib_abort_offset(self, env: Env, httpd, nghttpx, proto, repeat): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_ossl_quic(): -+ pytest.skip('OpenSSL QUIC fails here') -+ if proto == 'h3' and env.ci_run and env.curl_uses_lib('quiche'): -+ pytest.skip("fails in CI, but works locally for unknown reasons") -+ count = 10 -+ max_parallel = 5 -+ if proto in ['h2', 'h3']: -+ abort_offset = 64 * 1024 -+ else: -+ abort_offset = 12 * 1024 -+ docname = 'data-1m' - url = f'https://localhost:{env.https_port}/{docname}' -- client = LocalClient(name='h2-download', env=env) -+ client = LocalClient(name='hx-download', env=env) - if not client.exists(): - pytest.skip(f'example client not built: {client.name}') - r = client.run(args=[ - '-n', f'{count}', '-m', f'{max_parallel}', '-a', -- '-P', f'{pause_offset}', url -+ '-A', f'{abort_offset}', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ srcfile = os.path.join(httpd.docs_dir, docname) -+ # downloads should be there, but not necessarily complete -+ self.check_downloads(client, srcfile, count, complete=False) -+ -+ # download, several at a time, abort after n bytes -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_23c_lib_fail_offset(self, env: Env, httpd, nghttpx, proto, repeat): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_ossl_quic(): -+ pytest.skip('OpenSSL QUIC fails here') -+ if proto == 'h3' and env.ci_run and env.curl_uses_lib('quiche'): -+ pytest.skip("fails in CI, but works locally for unknown reasons") -+ count = 10 -+ max_parallel = 5 -+ if proto in ['h2', 'h3']: -+ fail_offset = 64 * 1024 -+ else: -+ fail_offset = 12 * 1024 -+ docname = 'data-1m' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-m', f'{max_parallel}', '-a', -+ '-F', f'{fail_offset}', '-V', proto, url - ]) - r.check_exit_code(0) - srcfile = os.path.join(httpd.docs_dir, docname) -@@ -345,29 +452,26 @@ class TestDownload: - self.check_downloads(client, srcfile, count, complete=False) - - # speed limited download -- @pytest.mark.parametrize("proto", ['h2', 'h3']) -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) - def test_02_24_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") - count = 1 - url = f'https://{env.authority_for(env.domain1, proto)}/data-1m' - curl = CurlClient(env=env) -+ speed_limit = 384 * 1024 -+ min_duration = math.floor((1024 * 1024)/speed_limit) - r = curl.http_download(urls=[url], alpn_proto=proto, extra_args=[ -- '--limit-rate', f'{196 * 1024}' -+ '--limit-rate', f'{speed_limit}' - ]) - r.check_response(count=count, http_status=200) -- assert r.duration > timedelta(seconds=4), \ -- f'rate limited transfer should take more than 4s, not {r.duration}' -+ assert r.duration > timedelta(seconds=min_duration), \ -+ f'rate limited transfer should take more than {min_duration}s, '\ -+ f'not {r.duration}' - - # make extreme parallel h2 upgrades, check invalid conn reuse - # before protocol switch has happened - def test_02_25_h2_upgrade_x(self, env: Env, httpd, repeat): -- # not locally reproducible timeouts with certain SSL libs -- # Since this test is about connection reuse handling, we skip -- # it on these builds. Although we would certainly like to understand -- # why this happens. -- if env.curl_uses_lib('bearssl'): -- pytest.skip('CI workflows timeout on bearssl build') - url = f'http://localhost:{env.http_port}/data-100k' - client = LocalClient(name='h2-upgrade-extreme', env=env, timeout=15) - if not client.exists(): -@@ -376,24 +480,56 @@ class TestDownload: - assert r.exit_code == 0, f'{client.dump_logs()}' - - # Special client that tests TLS session reuse in parallel transfers -- def test_02_26_session_shared_reuse(self, env: Env, httpd, repeat): -- curl = CurlClient(env=env) -- url = f'https://{env.domain1}:{env.https_port}/data-100k' -+ # TODO: just uses a single connection for h2/h3. Not sure how to prevent that -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_26_session_shared_reuse(self, env: Env, proto, httpd, nghttpx, repeat): -+ url = f'https://{env.authority_for(env.domain1, proto)}/data-100k' - client = LocalClient(name='tls-session-reuse', env=env) - if not client.exists(): - pytest.skip(f'example client not built: {client.name}') -- r = client.run(args=[url]) -+ r = client.run(args=[proto, url]) - r.check_exit_code(0) - - # test on paused transfers, based on issue #11982 -- def test_02_27_paused_no_cl(self, env: Env, httpd, nghttpx, repeat): -- proto = 'h2' -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_27a_paused_no_cl(self, env: Env, httpd, nghttpx, proto, repeat): - url = f'https://{env.authority_for(env.domain1, proto)}' \ -- '/tweak?&chunks=2&chunk_size=16000' -+ '/curltest/tweak/?&chunks=6&chunk_size=8000' - client = LocalClient(env=env, name='h2-pausing') -- r = client.run(args=[url]) -+ r = client.run(args=['-V', proto, url]) - r.check_exit_code(0) - -+ # test on paused transfers, based on issue #11982 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_27b_paused_no_cl(self, env: Env, httpd, nghttpx, proto, repeat): -+ url = f'https://{env.authority_for(env.domain1, proto)}' \ -+ '/curltest/tweak/?error=502' -+ client = LocalClient(env=env, name='h2-pausing') -+ r = client.run(args=['-V', proto, url]) -+ r.check_exit_code(0) -+ -+ # test on paused transfers, based on issue #11982 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_27c_paused_no_cl(self, env: Env, httpd, nghttpx, proto, repeat): -+ url = f'https://{env.authority_for(env.domain1, proto)}' \ -+ '/curltest/tweak/?status=200&chunks=1&chunk_size=100' -+ client = LocalClient(env=env, name='h2-pausing') -+ r = client.run(args=['-V', proto, url]) -+ r.check_exit_code(0) -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_28_get_compressed(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 1 -+ urln = f'https://{env.authority_for(env.domain1brotli, proto)}/data-100k?[0-{count-1}]' -+ curl = CurlClient(env=env) -+ r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -+ '--compressed' -+ ]) -+ r.check_exit_code(code=0) -+ r.check_response(count=count, http_status=200) -+ - def check_downloads(self, client, srcfile: str, count: int, - complete: bool = True): - for i in range(count): -@@ -406,3 +542,94 @@ class TestDownload: - tofile=dfile, - n=1)) - assert False, f'download {dfile} differs:\n{diff}' -+ -+ # download via lib client, 1 at a time, pause/resume at different offsets -+ @pytest.mark.parametrize("pause_offset", [0, 10*1024, 100*1023, 640000]) -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_29_h2_lib_serial(self, env: Env, httpd, nghttpx, proto, pause_offset, repeat): -+ count = 2 -+ docname = 'data-10m' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-P', f'{pause_offset}', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ srcfile = os.path.join(httpd.docs_dir, docname) -+ self.check_downloads(client, srcfile, count) -+ -+ # download parallel with prior knowledge -+ def test_02_30_parallel_prior_knowledge(self, env: Env, httpd): -+ count = 3 -+ curl = CurlClient(env=env) -+ urln = f'http://{env.domain1}:{env.http_port}/data.json?[0-{count-1}]' -+ r = curl.http_download(urls=[urln], extra_args=[ -+ '--parallel', '--http2-prior-knowledge' -+ ]) -+ r.check_response(http_status=200, count=count) -+ assert r.total_connects == 1, r.dump_logs() -+ -+ # download parallel with h2 "Upgrade:" -+ def test_02_31_parallel_upgrade(self, env: Env, httpd, nghttpx): -+ count = 3 -+ curl = CurlClient(env=env) -+ urln = f'http://{env.domain1}:{env.http_port}/data.json?[0-{count-1}]' -+ r = curl.http_download(urls=[urln], extra_args=[ -+ '--parallel', '--http2' -+ ]) -+ r.check_response(http_status=200, count=count) -+ # we see 3 connections, because Apache only every serves a single -+ # request via Upgrade: and then closed the connection. -+ assert r.total_connects == 3, r.dump_logs() -+ -+ # nghttpx is the only server we have that supports TLS early data -+ @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx") -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto): -+ if not env.curl_uses_lib('gnutls'): -+ pytest.skip('TLS earlydata only implemented in GnuTLS') -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 -+ docname = 'data-10k' -+ # we want this test to always connect to nghttpx, since it is -+ # the only server we have that supports TLS earlydata -+ port = env.port_for(proto) -+ if proto != 'h3': -+ port = env.nghttpx_https_port -+ url = f'https://{env.domain1}:{port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', -+ '-e', # use TLS earlydata -+ '-f', # forbid reuse of connections -+ '-r', f'{env.domain1}:{port}:127.0.0.1', -+ '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ srcfile = os.path.join(httpd.docs_dir, docname) -+ self.check_downloads(client, srcfile, count) -+ # check that TLS earlydata worked as expected -+ earlydata = {} -+ reused_session = False -+ for line in r.trace_lines: -+ m = re.match(r'^\[t-(\d+)] EarlyData: (\d+)', line) -+ if m: -+ earlydata[int(m.group(1))] = int(m.group(2)) -+ continue -+ m = re.match(r'\[1-1] \* SSL reusing session.*', line) -+ if m: -+ reused_session = True -+ assert reused_session, 'session was not reused for 2nd transfer' -+ assert earlydata[0] == 0, f'{earlydata}' -+ if proto == 'http/1.1': -+ assert earlydata[1] == 69, f'{earlydata}' -+ elif proto == 'h2': -+ assert earlydata[1] == 107, f'{earlydata}' -+ elif proto == 'h3': -+ # not implemented -+ assert earlydata[1] == 0, f'{earlydata}' -diff --git a/tests/http/test_03_goaway.py b/tests/http/test_03_goaway.py -index 1f4a3d784..26d57bbe3 100644 ---- a/tests/http/test_03_goaway.py -+++ b/tests/http/test_03_goaway.py -@@ -36,7 +36,6 @@ from testenv import Env, CurlClient, ExecResult - log = logging.getLogger(__name__) - - --@pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs") - class TestGoAway: - - @pytest.fixture(autouse=True, scope='class') -@@ -83,8 +82,8 @@ class TestGoAway: - proto = 'h3' - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") -- if proto == 'h3' and env.curl_uses_lib('quiche'): -- pytest.skip("does not work in CI, but locally for some reason") -+ if proto == 'h3' and env.curl_uses_ossl_quic(): -+ pytest.skip('OpenSSL QUIC fails here') - count = 3 - self.r = None - def long_run(): -@@ -103,8 +102,8 @@ class TestGoAway: - assert nghttpx.reload(timeout=timedelta(seconds=2)) - t.join() - r: ExecResult = self.r -- # this should take `count` seconds to retrieve -- assert r.duration >= timedelta(seconds=count) -+ # this should take `count` seconds to retrieve, maybe a little less -+ assert r.duration >= timedelta(seconds=count-1) - r.check_response(count=count, http_status=200, connect_count=2) - # reload will shut down the connection gracefully with GOAWAY - # we expect to see a second connection opened afterwards -@@ -120,10 +119,13 @@ class TestGoAway: - def long_run(): - curl = CurlClient(env=env) - # send 10 chunks of 1024 bytes in a response body with 100ms delay in between -+ # pause 2 seconds between requests - urln = f'https://{env.authority_for(env.domain1, proto)}' \ - f'/curltest/tweak?id=[0-{count - 1}]'\ - '&chunks=10&chunk_size=1024&chunk_delay=100ms' -- self.r = curl.http_download(urls=[urln], alpn_proto=proto) -+ self.r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[ -+ '--rate', '30/m', -+ ]) - - t = Thread(target=long_run) - t.start() -@@ -134,7 +136,7 @@ class TestGoAway: - t.join() - r: ExecResult = self.r - r.check_response(count=count, http_status=200, connect_count=2) -- # reload will shut down the connection gracefully with GOAWAY -+ # reload will shut down the connection gracefully - # we expect to see a second connection opened afterwards - for idx, s in enumerate(r.stats): - if s['num_connects'] > 0: -diff --git a/tests/http/test_04_stuttered.py b/tests/http/test_04_stuttered.py -index e017a44c3..c5463cc94 100644 ---- a/tests/http/test_04_stuttered.py -+++ b/tests/http/test_04_stuttered.py -@@ -25,7 +25,6 @@ - ########################################################################### - # - import logging --import os - from typing import Tuple, List, Dict - import pytest - -diff --git a/tests/http/test_05_errors.py b/tests/http/test_05_errors.py -index 68e49f736..a496d6d8b 100644 ---- a/tests/http/test_05_errors.py -+++ b/tests/http/test_05_errors.py -@@ -24,12 +24,10 @@ - # - ########################################################################### - # --import json - import logging --from typing import Optional, Tuple, List, Dict - import pytest - --from testenv import Env, CurlClient, ExecResult -+from testenv import Env, CurlClient - - - log = logging.getLogger(__name__) -@@ -129,9 +127,11 @@ class TestErrors: - r = curl.http_download(urls=[url], alpn_proto=proto, extra_args=[ - '--parallel', - ]) -- if proto == 'http/1.0': -+ if proto == 'http/1.0' and not env.curl_uses_lib('wolfssl') and \ -+ (env.curl_is_debug() or not env.curl_uses_lib('openssl')): -+ # we are inconsistent if we fail or not in missing TLS shutdown -+ # openssl code ignore such errors intentionally in non-debug builds - r.check_exit_code(56) - else: - r.check_exit_code(0) - r.check_response(http_status=200, count=count) -- -diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py -index 8a93440c5..0c553958d 100644 ---- a/tests/http/test_06_eyeballs.py -+++ b/tests/http/test_06_eyeballs.py -@@ -24,12 +24,10 @@ - # - ########################################################################### - # --import json - import logging --from typing import Optional, Tuple, List, Dict - import pytest - --from testenv import Env, CurlClient, ExecResult -+from testenv import Env, CurlClient - - - log = logging.getLogger(__name__) -@@ -45,7 +43,7 @@ class TestEyeballs: - httpd.reload() - - # download using only HTTP/3 on working server -- @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") -+ @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") - def test_06_01_h3_only(self, env: Env, httpd, nghttpx, repeat): - curl = CurlClient(env=env) - urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' -@@ -54,7 +52,7 @@ class TestEyeballs: - assert r.stats[0]['http_version'] == '3' - - # download using only HTTP/3 on missing server -- @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") -+ @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") - def test_06_02_h3_only(self, env: Env, httpd, nghttpx, repeat): - nghttpx.stop_if_running() - curl = CurlClient(env=env) -@@ -63,7 +61,7 @@ class TestEyeballs: - r.check_response(exitcode=7, http_status=None) - - # download using HTTP/3 on missing server with fallback on h2 -- @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") -+ @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") - def test_06_03_h3_fallback_h2(self, env: Env, httpd, nghttpx, repeat): - nghttpx.stop_if_running() - curl = CurlClient(env=env) -@@ -73,7 +71,7 @@ class TestEyeballs: - assert r.stats[0]['http_version'] == '2' - - # download using HTTP/3 on missing server with fallback on http/1.1 -- @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") -+ @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") - def test_06_04_h3_fallback_h1(self, env: Env, httpd, nghttpx, repeat): - nghttpx.stop_if_running() - curl = CurlClient(env=env) -@@ -105,7 +103,7 @@ class TestEyeballs: - # make https: to an invalid address - def test_06_12_stats_fail_tcp(self, env: Env, httpd, nghttpx, repeat): - curl = CurlClient(env=env) -- urln = f'https://not-valid.com:1/data.json' -+ urln = 'https://not-valid.com:1/data.json' - r = curl.http_download(urls=[urln], extra_args=[ - '--resolve', f'not-valid.com:{1}:127.0.0.1' - ]) -diff --git a/tests/http/test_07_upload.py b/tests/http/test_07_upload.py -index d7ff1682b..2ce2707cc 100644 ---- a/tests/http/test_07_upload.py -+++ b/tests/http/test_07_upload.py -@@ -28,10 +28,11 @@ import difflib - import filecmp - import logging - import os --import time -+import re - import pytest -+from typing import List - --from testenv import Env, CurlClient -+from testenv import Env, CurlClient, LocalClient - - - log = logging.getLogger(__name__) -@@ -43,6 +44,7 @@ class TestUpload: - def _class_scope(self, env, httpd, nghttpx): - if env.have_h3(): - nghttpx.start_if_needed() -+ env.make_data_file(indir=env.gen_dir, fname="data-10k", fsize=10*1024) - env.make_data_file(indir=env.gen_dir, fname="data-63k", fsize=63*1024) - env.make_data_file(indir=env.gen_dir, fname="data-64k", fsize=64*1024) - env.make_data_file(indir=env.gen_dir, fname="data-100k", fsize=100*1024) -@@ -89,7 +91,7 @@ class TestUpload: - pytest.skip("h3 not supported") - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") -- count = 50 -+ count = 20 - data = '0123456789' - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' -@@ -107,7 +109,7 @@ class TestUpload: - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") - # limit since we use a separate connection in h1 -- count = 50 -+ count = 20 - data = '0123456789' - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' -@@ -126,7 +128,7 @@ class TestUpload: - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") - fdata = os.path.join(env.gen_dir, 'data-100k') -- count = 20 -+ count = 10 - 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) -@@ -155,6 +157,73 @@ class TestUpload: - respdata = open(curl.response_file(i)).readlines() - assert respdata == indata - -+ # upload from stdin, issue #14870 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ @pytest.mark.parametrize("indata", [ -+ '', '1', '123\n456andsomething\n\n' -+ ]) -+ def test_07_14_upload_stdin(self, env: Env, httpd, nghttpx, proto, indata): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 stalls here") -+ count = 1 -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-{count-1}]' -+ r = curl.http_put(urls=[url], data=indata, alpn_proto=proto) -+ r.check_stats(count=count, http_status=200, exitcode=0) -+ for i in range(count): -+ respdata = open(curl.response_file(i)).readlines() -+ assert respdata == [f'{len(indata)}'] -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_15_hx_put(self, env: Env, httpd, nghttpx, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 -+ upload_size = 128*1024 -+ url = f'https://localhost:{env.https_port}/curltest/put?id=[0-{count-1}]' -+ client = LocalClient(name='hx-upload', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-S', f'{upload_size}', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ self.check_downloads(client, [f"{upload_size}"], count) -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_16_hx_put_reuse(self, env: Env, httpd, nghttpx, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 -+ upload_size = 128*1024 -+ url = f'https://localhost:{env.https_port}/curltest/put?id=[0-{count-1}]' -+ client = LocalClient(name='hx-upload', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-S', f'{upload_size}', '-R', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ self.check_downloads(client, [f"{upload_size}"], count) -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_17_hx_post_reuse(self, env: Env, httpd, nghttpx, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 -+ upload_size = 128*1024 -+ url = f'https://localhost:{env.https_port}/curltest/echo?id=[0-{count-1}]' -+ client = LocalClient(name='hx-upload', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-M', 'POST', '-S', f'{upload_size}', '-R', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ self.check_downloads(client, ["x" * upload_size], count) -+ - # upload data parallel, check that they were echoed - @pytest.mark.parametrize("proto", ['h2', 'h3']) - def test_07_20_upload_parallel(self, env: Env, httpd, nghttpx, repeat, proto): -@@ -163,7 +232,7 @@ class TestUpload: - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") - # limit since we use a separate connection in h1 -- count = 20 -+ count = 10 - data = '0123456789' - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-{count-1}]' -@@ -183,7 +252,7 @@ class TestUpload: - pytest.skip("msh3 stalls here") - fdata = os.path.join(env.gen_dir, 'data-100k') - # limit since we use a separate connection in h1 -- count = 20 -+ count = 10 - 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, -@@ -199,7 +268,7 @@ class TestUpload: - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 stalls here") - fdata = os.path.join(env.gen_dir, 'data-10m') -- count = 100 -+ count = 20 - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}'\ - f'/curltest/tweak?status=400&delay=5ms&chunks=1&body_error=reset&id=[0-{count-1}]' -@@ -464,6 +533,78 @@ class TestUpload: - n=1)) - assert False, f'download {dfile} differs:\n{diff}' - -+ # upload data, pause, let connection die with an incomplete response -+ # issues #11769 #13260 -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_42a_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 fails here") -+ client = LocalClient(name='upload-pausing', env=env, timeout=60) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&die_after=0' -+ r = client.run(['-V', proto, url]) -+ if r.exit_code == 18: # PARTIAL_FILE is always ok -+ pass -+ elif proto == 'h2': -+ r.check_exit_code(92) # CURLE_HTTP2_STREAM also ok -+ elif proto == 'h3': -+ r.check_exit_code(95) # CURLE_HTTP3 also ok -+ else: -+ r.check_exit_code(18) # will fail as it should -+ -+ # upload data, pause, let connection die without any response at all -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_42b_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 fails here") -+ client = LocalClient(name='upload-pausing', env=env, timeout=60) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&just_die=1' -+ r = client.run(['-V', proto, url]) -+ exp_code = 52 # GOT_NOTHING -+ if proto == 'h2' or proto == 'h3': -+ exp_code = 0 # we get a 500 from the server -+ r.check_exit_code(exp_code) # GOT_NOTHING -+ -+ # upload data, pause, let connection die after 100 continue -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_42c_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 fails here") -+ client = LocalClient(name='upload-pausing', env=env, timeout=60) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]&die_after_100=1' -+ r = client.run(['-V', proto, url]) -+ exp_code = 52 # GOT_NOTHING -+ if proto == 'h2' or proto == 'h3': -+ exp_code = 0 # we get a 500 from the server -+ r.check_exit_code(exp_code) # GOT_NOTHING -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_07_43_upload_denied(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 fails here") -+ fdata = os.path.join(env.gen_dir, 'data-10m') -+ count = 1 -+ max_upload = 128 * 1024 -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?'\ -+ f'id=[0-{count-1}]&max_upload={max_upload}' -+ r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, -+ extra_args=['--trace-config', 'all']) -+ r.check_stats(count=count, http_status=413, exitcode=0) -+ - # speed limited on put handler - @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) - def test_07_50_put_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat): -@@ -472,7 +613,7 @@ class TestUpload: - count = 1 - fdata = os.path.join(env.gen_dir, 'data-100k') - up_len = 100 * 1024 -- speed_limit = 20 * 1024 -+ speed_limit = 50 * 1024 - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-0]' - r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, -@@ -491,7 +632,7 @@ class TestUpload: - pytest.skip("h3 not supported") - count = 1 - fdata = os.path.join(env.gen_dir, 'data-100k') -- speed_limit = 20 * 1024 -+ speed_limit = 50 * 1024 - curl = CurlClient(env=env) - url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' - r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, -@@ -528,3 +669,60 @@ class TestUpload: - ]) - r.check_stats(count=1, http_status=200, exitcode=0) - -+ # nghttpx is the only server we have that supports TLS early data and -+ # has a limit of 16k it announces -+ @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx") -+ @pytest.mark.parametrize("proto,upload_size,exp_early", [ -+ ['http/1.1', 100, 203], # headers+body -+ ['http/1.1', 10*1024, 10345], # headers+body -+ ['http/1.1', 32*1024, 16384], # headers+body, limited by server max -+ ['h2', 10*1024, 10378], # headers+body -+ ['h2', 32*1024, 16384], # headers+body, limited by server max -+ ['h3', 1024, 0], # earlydata not supported -+ ]) -+ def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, exp_early): -+ if not env.curl_uses_lib('gnutls'): -+ pytest.skip('TLS earlydata only implemented in GnuTLS') -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 2 -+ # we want this test to always connect to nghttpx, since it is -+ # the only server we have that supports TLS earlydata -+ port = env.port_for(proto) -+ if proto != 'h3': -+ port = env.nghttpx_https_port -+ url = f'https://{env.domain1}:{port}/curltest/put?id=[0-{count-1}]' -+ client = LocalClient(name='hx-upload', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', -+ '-e', # use TLS earlydata -+ '-f', # forbid reuse of connections -+ '-l', # announce upload length, no 'Expect: 100' -+ '-S', f'{upload_size}', -+ '-r', f'{env.domain1}:{port}:127.0.0.1', -+ '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ self.check_downloads(client, [f"{upload_size}"], count) -+ earlydata = {} -+ for line in r.trace_lines: -+ m = re.match(r'^\[t-(\d+)] EarlyData: (\d+)', line) -+ if m: -+ earlydata[int(m.group(1))] = int(m.group(2)) -+ assert earlydata[0] == 0, f'{earlydata}' -+ assert earlydata[1] == exp_early, f'{earlydata}' -+ -+ def check_downloads(self, client, source: List[str], count: int, -+ complete: bool = True): -+ for i in range(count): -+ dfile = client.download_file(i) -+ assert os.path.exists(dfile) -+ if complete: -+ diff = "".join(difflib.unified_diff(a=source, -+ b=open(dfile).readlines(), -+ fromfile='-', -+ tofile=dfile, -+ n=1)) -+ assert not diff, f'download {dfile} differs:\n{diff}' -diff --git a/tests/http/test_08_caddy.py b/tests/http/test_08_caddy.py -index c35bd27b7..335f76e6f 100644 ---- a/tests/http/test_08_caddy.py -+++ b/tests/http/test_08_caddy.py -@@ -24,18 +24,21 @@ - # - ########################################################################### - # -+import difflib -+import filecmp - import logging - import os -+import re - import pytest - --from testenv import Env, CurlClient, Caddy -+from testenv import Env, CurlClient, Caddy, LocalClient - - - log = logging.getLogger(__name__) - - --@pytest.mark.skipif(condition=not Env.has_caddy(), reason=f"missing caddy") --@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+@pytest.mark.skipif(condition=not Env.has_caddy(), reason="missing caddy") -+@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - class TestCaddy: - - @pytest.fixture(autouse=True, scope='class') -@@ -57,10 +60,12 @@ class TestCaddy: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env, caddy): -+ self._make_docs_file(docs_dir=caddy.docs_dir, fname='data10k.data', fsize=10*1024) - self._make_docs_file(docs_dir=caddy.docs_dir, fname='data1.data', fsize=1024*1024) - self._make_docs_file(docs_dir=caddy.docs_dir, fname='data5.data', fsize=5*1024*1024) - self._make_docs_file(docs_dir=caddy.docs_dir, fname='data10.data', fsize=10*1024*1024) - self._make_docs_file(docs_dir=caddy.docs_dir, fname='data100.data', fsize=100*1024*1024) -+ env.make_data_file(indir=env.gen_dir, fname="data-10m", fsize=10*1024*1024) - - # download 1 file - @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -@@ -151,6 +156,9 @@ class TestCaddy: - pytest.skip("h3 not supported in curl") - if proto == 'h3' and env.curl_uses_lib('msh3'): - pytest.skip("msh3 itself crashes") -+ if proto == 'http/1.1' and env.curl_uses_lib('mbedtls'): -+ pytest.skip("mbedtls 3.6.0 fails on 50 connections with: "\ -+ "ssl_handshake returned: (-0x7F00) SSL - Memory allocation failed") - count = 50 - curl = CurlClient(env=env) - urln = f'https://{env.domain1}:{caddy.port}/data10.data?[0-{count-1}]' -@@ -164,10 +172,9 @@ class TestCaddy: - else: - assert r.total_connects == 1, r.dump_logs() - -- # upload data parallel, check that they were echoed -- @pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs") -- @pytest.mark.parametrize("proto", ['h2', 'h3']) -- def test_08_06_upload_parallel(self, env: Env, caddy, repeat, proto): -+ # post data parallel, check that they were echoed -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_08_06_post_parallel(self, env: Env, httpd, caddy, repeat, proto): - if proto == 'h3' and not env.have_h3(): - pytest.skip("h3 not supported") - if proto == 'h3' and env.curl_uses_lib('msh3'): -@@ -176,7 +183,69 @@ class TestCaddy: - count = 20 - data = '0123456789' - curl = CurlClient(env=env) -- url = f'https://{env.domain1}:{caddy.port}/data10.data?[0-{count-1}]' -+ url = f'https://{env.domain2}:{caddy.port}/curltest/echo?id=[0-{count-1}]' - r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, - extra_args=['--parallel']) - r.check_stats(count=count, http_status=200, exitcode=0) -+ for i in range(count): -+ respdata = open(curl.response_file(i)).readlines() -+ assert respdata == [data] -+ -+ # put large file, check that they length were echoed -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_08_07_put_large(self, env: Env, httpd, caddy, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if proto == 'h3' and env.curl_uses_lib('msh3'): -+ pytest.skip("msh3 stalls here") -+ # limit since we use a separate connection in h1< -+ count = 1 -+ fdata = os.path.join(env.gen_dir, 'data-10m') -+ curl = CurlClient(env=env) -+ url = f'https://{env.domain2}:{caddy.port}/curltest/put?id=[0-{count-1}]' -+ r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto) -+ exp_data = [f'{os.path.getsize(fdata)}'] -+ r.check_response(count=count, http_status=200) -+ for i in range(count): -+ respdata = open(curl.response_file(i)).readlines() -+ assert respdata == exp_data -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) -+ def test_08_08_earlydata(self, env: Env, httpd, caddy, proto): -+ count = 2 -+ docname = 'data10k.data' -+ url = f'https://{env.domain1}:{caddy.port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', -+ '-e', # use TLS earlydata -+ '-f', # forbid reuse of connections -+ '-r', f'{env.domain1}:{caddy.port}:127.0.0.1', -+ '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ srcfile = os.path.join(caddy.docs_dir, docname) -+ self.check_downloads(client, srcfile, count) -+ earlydata = {} -+ for line in r.trace_lines: -+ m = re.match(r'^\[t-(\d+)] EarlyData: (\d+)', line) -+ if m: -+ earlydata[int(m.group(1))] = int(m.group(2)) -+ # Caddy does not support early data -+ assert earlydata[0] == 0, f'{earlydata}' -+ assert earlydata[1] == 0, f'{earlydata}' -+ -+ def check_downloads(self, client, srcfile: str, count: int, -+ complete: bool = True): -+ for i in range(count): -+ dfile = client.download_file(i) -+ assert os.path.exists(dfile) -+ if complete and not filecmp.cmp(srcfile, dfile, shallow=False): -+ diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), -+ b=open(dfile).readlines(), -+ fromfile=srcfile, -+ tofile=dfile, -+ n=1)) -+ assert False, f'download {dfile} differs:\n{diff}' -diff --git a/tests/http/test_09_push.py b/tests/http/test_09_push.py -index 900741505..6b36d2f27 100644 ---- a/tests/http/test_09_push.py -+++ b/tests/http/test_09_push.py -@@ -45,14 +45,14 @@ class TestPush: - env.make_data_file(indir=push_dir, fname="data2", fsize=1*1024) - env.make_data_file(indir=push_dir, fname="data3", fsize=1*1024) - httpd.set_extra_config(env.domain1, [ -- f'H2EarlyHints on', -- f'', -- f' H2PushResource /push/data2', -- f'', -- f'', -- f' H2PushResource /push/data1', -- f' H2PushResource /push/data3', -- f'', -+ 'H2EarlyHints on', -+ '', -+ ' H2PushResource /push/data2', -+ '', -+ '', -+ ' H2PushResource /push/data1', -+ ' H2PushResource /push/data3', -+ '', - ]) - # activate the new config - httpd.reload() -diff --git a/tests/http/test_10_proxy.py b/tests/http/test_10_proxy.py -index c191432fb..2ebf66789 100644 ---- a/tests/http/test_10_proxy.py -+++ b/tests/http/test_10_proxy.py -@@ -51,8 +51,8 @@ class TestProxy: - httpd.reload() - - def get_tunnel_proto_used(self, r: ExecResult): -- for l in r.trace_lines: -- m = re.match(r'.* CONNECT tunnel: (\S+) negotiated$', l) -+ for line in r.trace_lines: -+ m = re.match(r'.* CONNECT tunnel: (\S+) negotiated$', line) - if m: - return m.group(1) - assert False, f'tunnel protocol not found in:\n{"".join(r.trace_lines)}' -@@ -82,7 +82,7 @@ class TestProxy: - protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') - - # upload via https: with proto (no tunnel) -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) - @pytest.mark.parametrize("fname, fcount", [ - ['data.json', 5], -@@ -132,7 +132,7 @@ class TestProxy: - - # download https: with proto via http: proxytunnel - @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - def test_10_05_proxytunnel_http(self, env: Env, httpd, proto, repeat): - curl = CurlClient(env=env) - url = f'https://localhost:{env.https_port}/data.json' -@@ -165,7 +165,7 @@ class TestProxy: - assert filecmp.cmp(srcfile, dfile, shallow=False) - - # download many https: with proto via https: proxytunnel -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.parametrize("fname, fcount", [ -@@ -195,7 +195,7 @@ class TestProxy: - assert r.total_connects == 1, r.dump_logs() - - # upload many https: with proto via https: proxytunnel -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.parametrize("fname, fcount", [ -@@ -221,10 +221,10 @@ class TestProxy: - indata = open(srcfile).readlines() - for i in range(count): - respdata = open(curl.response_file(i)).readlines() -- assert respdata == indata -+ assert respdata == indata, f'resonse {i} differs' - assert r.total_connects == 1, r.dump_logs() - -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") - def test_10_09_reuse_ser(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat): -@@ -247,7 +247,7 @@ class TestProxy: - else: - assert r.total_connects == 2 - -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") - def test_10_10_reuse_proxy(self, env: Env, httpd, nghttpx_fwd, tunnel, repeat): -@@ -271,7 +271,7 @@ class TestProxy: - r2.check_response(count=2, http_status=200) - assert r2.total_connects == 1 - -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") - @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") -@@ -291,13 +291,13 @@ class TestProxy: - x2_args = r1.args[1:] - x2_args.append('--next') - x2_args.extend(proxy_args) -- x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_128_GCM_SHA256']) -+ x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384']) - r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, - extra_args=x2_args) - r2.check_response(count=2, http_status=200) - assert r2.total_connects == 2 - -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") - @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") -@@ -317,13 +317,13 @@ class TestProxy: - x2_args = r1.args[1:] - x2_args.append('--next') - x2_args.extend(proxy_args) -- x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_128_GCM_SHA256']) -+ x2_args.extend(['--proxy-tls13-ciphers', 'TLS_AES_256_GCM_SHA384']) - r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, - extra_args=x2_args) - r2.check_response(count=2, http_status=200) - assert r2.total_connects == 2 - -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - @pytest.mark.parametrize("tunnel", ['http/1.1', 'h2']) - @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available") - @pytest.mark.skipif(condition=not Env.curl_uses_lib('openssl'), reason="tls13-ciphers not supported") -@@ -343,7 +343,7 @@ class TestProxy: - x2_args = r1.args[1:] - x2_args.append('--next') - x2_args.extend(proxy_args) -- x2_args.extend(['--tls13-ciphers', 'TLS_AES_128_GCM_SHA256']) -+ x2_args.extend(['--tls13-ciphers', 'TLS_AES_256_GCM_SHA384']) - r2 = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, - extra_args=x2_args) - r2.check_response(count=2, http_status=200) -@@ -368,4 +368,3 @@ class TestProxy: - else: - r.check_response(count=1, http_status=200, - protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') -- -diff --git a/tests/http/test_11_unix.py b/tests/http/test_11_unix.py -index dc2684adb..1fe569279 100644 ---- a/tests/http/test_11_unix.py -+++ b/tests/http/test_11_unix.py -@@ -28,6 +28,8 @@ import logging - import os - import socket - from threading import Thread -+from typing import Generator -+ - import pytest - - from testenv import Env, CurlClient -@@ -40,6 +42,7 @@ class UDSFaker: - def __init__(self, path): - self._uds_path = path - self._done = False -+ self._socket = None - - @property - def path(self): -@@ -69,7 +72,7 @@ class UDSFaker: - try: - c, client_address = self._socket.accept() - try: -- data = c.recv(16) -+ c.recv(16) - c.sendall("""HTTP/1.1 200 Ok - Server: UdsFaker - Content-Type: application/json -@@ -81,19 +84,21 @@ Content-Length: 19 - - except ConnectionAbortedError: - self._done = True -+ except OSError: -+ self._done = True - - - class TestUnix: - - @pytest.fixture(scope="class") -- def uds_faker(self, env: Env) -> UDSFaker: -+ def uds_faker(self, env: Env) -> Generator[UDSFaker, None, None]: - uds_path = os.path.join(env.gen_dir, 'uds_11.sock') - faker = UDSFaker(path=uds_path) - faker.start() - yield faker - faker.stop() - -- # download http: via unix socket -+ # download http: via Unix socket - def test_11_01_unix_connect_http(self, env: Env, httpd, uds_faker, repeat): - curl = CurlClient(env=env) - url = f'http://{env.domain1}:{env.http_port}/data.json' -@@ -103,8 +108,8 @@ class TestUnix: - ]) - r.check_response(count=1, http_status=200) - -- # download https: via unix socket -- @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+ # download https: via Unix socket -+ @pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - def test_11_02_unix_connect_http(self, env: Env, httpd, uds_faker, repeat): - curl = CurlClient(env=env) - url = f'https://{env.domain1}:{env.https_port}/data.json' -@@ -114,7 +119,7 @@ class TestUnix: - ]) - r.check_response(exitcode=35, http_status=None) - -- # download HTTP/3 via unix socket -+ # download HTTP/3 via Unix socket - @pytest.mark.skipif(condition=not Env.have_h3(), reason='h3 not supported') - def test_11_03_unix_connect_quic(self, env: Env, httpd, uds_faker, repeat): - curl = CurlClient(env=env) -diff --git a/tests/http/test_12_reuse.py b/tests/http/test_12_reuse.py -index 83bfadfe4..9252f2474 100644 ---- a/tests/http/test_12_reuse.py -+++ b/tests/http/test_12_reuse.py -@@ -24,10 +24,9 @@ - # - ########################################################################### - # --import difflib --import filecmp - import logging - import os -+from datetime import datetime, timedelta - import pytest - - from testenv import Env, CurlClient -@@ -36,8 +35,7 @@ from testenv import Env, CurlClient - log = logging.getLogger(__name__) - - --@pytest.mark.skipif(condition=Env.curl_uses_lib('bearssl'), reason='BearSSL too slow') --@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason=f"curl without SSL") -+@pytest.mark.skipif(condition=not Env.have_ssl_curl(), reason="curl without SSL") - class TestReuse: - - # check if HTTP/1.1 handles 'Connection: close' correctly -@@ -46,7 +44,7 @@ class TestReuse: - httpd, nghttpx, repeat, proto): - httpd.clear_extra_configs() - httpd.set_extra_config('base', [ -- f'MaxKeepAliveRequests 1', -+ 'MaxKeepAliveRequests 1', - ]) - httpd.reload() - count = 100 -@@ -59,12 +57,14 @@ class TestReuse: - delta = 5 - assert (count/2 - delta) < r.total_connects < (count/2 + delta) - -+ @pytest.mark.skipif(condition=Env.httpd_is_at_least('2.5.0'), -+ reason="httpd 2.5+ handles KeepAlives different") - @pytest.mark.parametrize("proto", ['http/1.1']) - def test_12_02_h1_conn_timeout(self, env: Env, - httpd, nghttpx, repeat, proto): - httpd.clear_extra_configs() - httpd.set_extra_config('base', [ -- f'KeepAliveTimeout 1', -+ 'KeepAliveTimeout 1', - ]) - httpd.reload() - count = 5 -@@ -76,3 +76,72 @@ class TestReuse: - r.check_response(count=count, http_status=200) - # Connections time out on server before we send another request, - assert r.total_connects == count -+ -+ @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") -+ def test_12_03_alt_svc_h2h3(self, env: Env, httpd, nghttpx): -+ httpd.clear_extra_configs() -+ httpd.reload() -+ count = 2 -+ # write a alt-svc file the advises h3 instead of h2 -+ asfile = os.path.join(env.gen_dir, 'alt-svc-12_03.txt') -+ ts = datetime.now() + timedelta(hours=24) -+ expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}' -+ with open(asfile, 'w') as fd: -+ fd.write(f'h2 {env.domain1} {env.https_port} h3 {env.domain1} {env.https_port} "{expires}" 0 0') -+ log.info(f'altscv: {open(asfile).readlines()}') -+ curl = CurlClient(env=env) -+ urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json?[0-{count-1}]' -+ r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ -+ '--alt-svc', f'{asfile}', -+ ]) -+ r.check_response(count=count, http_status=200) -+ # We expect the connection to be reused -+ assert r.total_connects == 1 -+ for s in r.stats: -+ assert s['http_version'] == '3', f'{s}' -+ -+ def test_12_04_alt_svc_h3h2(self, env: Env, httpd, nghttpx): -+ httpd.clear_extra_configs() -+ httpd.reload() -+ count = 2 -+ # write a alt-svc file the advises h2 instead of h3 -+ asfile = os.path.join(env.gen_dir, 'alt-svc-12_04.txt') -+ ts = datetime.now() + timedelta(hours=24) -+ expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}' -+ with open(asfile, 'w') as fd: -+ fd.write(f'h3 {env.domain1} {env.https_port} h2 {env.domain1} {env.https_port} "{expires}" 0 0') -+ log.info(f'altscv: {open(asfile).readlines()}') -+ curl = CurlClient(env=env) -+ urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json?[0-{count-1}]' -+ r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ -+ '--alt-svc', f'{asfile}', -+ ]) -+ r.check_response(count=count, http_status=200) -+ # We expect the connection to be reused -+ assert r.total_connects == 1 -+ for s in r.stats: -+ assert s['http_version'] == '2', f'{s}' -+ -+ def test_12_05_alt_svc_h3h1(self, env: Env, httpd, nghttpx): -+ httpd.clear_extra_configs() -+ httpd.reload() -+ count = 2 -+ # write a alt-svc file the advises h1 instead of h3 -+ asfile = os.path.join(env.gen_dir, 'alt-svc-12_05.txt') -+ ts = datetime.now() + timedelta(hours=24) -+ expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}' -+ with open(asfile, 'w') as fd: -+ fd.write(f'h3 {env.domain1} {env.https_port} http/1.1 {env.domain1} {env.https_port} "{expires}" 0 0') -+ log.info(f'altscv: {open(asfile).readlines()}') -+ curl = CurlClient(env=env) -+ urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json?[0-{count-1}]' -+ r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ -+ '--alt-svc', f'{asfile}', -+ ]) -+ r.check_response(count=count, http_status=200) -+ # We expect the connection to be reused -+ assert r.total_connects == 1 -+ # When using http/1.1 from alt-svc, we ALPN-negotiate 'h2,http/1.1' anyway -+ # which means our server gives us h2 -+ for s in r.stats: -+ assert s['http_version'] == '2', f'{s}' -diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py -index abeae0100..0979fbb7e 100644 ---- a/tests/http/test_13_proxy_auth.py -+++ b/tests/http/test_13_proxy_auth.py -@@ -24,11 +24,8 @@ - # - ########################################################################### - # --import filecmp - import logging --import os - import re --import time - import pytest - - from testenv import Env, CurlClient, ExecResult -diff --git a/tests/http/test_14_auth.py b/tests/http/test_14_auth.py -index b90817b62..8fa6767b0 100644 ---- a/tests/http/test_14_auth.py -+++ b/tests/http/test_14_auth.py -@@ -24,13 +24,11 @@ - # - ########################################################################### - # --import difflib --import filecmp - import logging - import os - import pytest - --from testenv import Env, CurlClient, LocalClient -+from testenv import Env, CurlClient - - - log = logging.getLogger(__name__) -diff --git a/tests/http/test_16_info.py b/tests/http/test_16_info.py -new file mode 100644 -index 000000000..06ab9503c ---- /dev/null -+++ b/tests/http/test_16_info.py -@@ -0,0 +1,169 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 logging -+import os -+import pytest -+ -+from testenv import Env, CurlClient -+ -+ -+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, exitcode=0, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ for idx, s in enumerate(r.stats): -+ self.check_stat(idx, s, r, 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, exitcode=0, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ for idx, s in enumerate(r.stats): -+ self.check_stat(idx, s, r, 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, extra_args=[ -+ '--trace-config', 'http/2,http/3' -+ ]) -+ r.check_response(count=count, http_status=200) -+ r.check_stats(count=count, http_status=200, exitcode=0, -+ remote_port=env.port_for(alpn_proto=proto), -+ remote_ip='127.0.0.1') -+ for idx, s in enumerate(r.stats): -+ self.check_stat(idx, s, r, 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, exitcode=0, -+ remote_port=env.http_port, remote_ip='127.0.0.1') -+ for idx, s in enumerate(r.stats): -+ self.check_stat(idx, s, r, dl_size=30, ul_size=0) -+ -+ def check_stat(self, idx, s, r, dl_size=None, ul_size=None): -+ self.check_stat_times(s, idx) -+ # we always send something -+ self.check_stat_positive(s, idx, 'size_request') -+ # we always receive response headers -+ self.check_stat_positive(s, idx, 'size_header') -+ if ul_size is not None: -+ assert s['size_upload'] == ul_size, f'stat #{idx}\n{r.dump_logs()}' # the file we sent -+ assert s['size_request'] >= s['size_upload'], \ -+ f'stat #{idx}, "size_request" smaller than "size_upload", {s}\n{r.dump_logs()}' -+ if dl_size is not None: -+ assert s['size_download'] == dl_size, f'stat #{idx}\n{r.dump_logs()}' # the file we received -+ -+ def check_stat_positive(self, s, idx, key): -+ assert key in s, f'stat #{idx} "{key}" missing: {s}' -+ assert s[key] > 0, f'stat #{idx} "{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, idx): -+ # check timings reported on a transfer for consistency -+ url = s['url_effective'] -+ # all stat keys which reporting timings -+ all_keys = { -+ 'time_appconnect', 'time_connect', 'time_redirect', -+ 'time_pretransfer', 'time_starttransfer', 'time_total' -+ } -+ # stat keys where we expect a positive value -+ pos_keys = {'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, idx, 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}' -diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py -new file mode 100644 -index 000000000..f129b1101 ---- /dev/null -+++ b/tests/http/test_17_ssl_use.py -@@ -0,0 +1,368 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 json -+import logging -+import os -+import re -+import pytest -+ -+from testenv import Env, CurlClient, LocalClient -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+class TestSSLUse: -+ -+ @pytest.fixture(autouse=True, scope='class') -+ def _class_scope(self, env, httpd, nghttpx): -+ env.make_data_file(indir=httpd.docs_dir, fname="data-10k", fsize=10*1024) -+ if env.have_h3(): -+ nghttpx.start_if_needed() -+ -+ @pytest.fixture(autouse=True, scope='function') -+ def _function_scope(self, request, env, httpd): -+ httpd.clear_extra_configs() -+ if 'httpd' not in request.node._fixtureinfo.argnames: -+ httpd.reload_if_config_changed() -+ -+ def test_17_01_sslinfo_plain(self, env: Env, nghttpx, repeat): -+ proto = 'http/1.1' -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto) -+ assert r.json['HTTPS'] == 'on', f'{r.json}' -+ assert 'SSL_SESSION_ID' in r.json, f'{r.json}' -+ assert 'SSL_SESSION_RESUMED' in r.json, f'{r.json}' -+ assert r.json['SSL_SESSION_RESUMED'] == 'Initial', f'{r.json}' -+ -+ @pytest.mark.parametrize("tls_max", ['1.2', '1.3']) -+ def test_17_02_sslinfo_reconnect(self, env: Env, tls_max): -+ proto = 'http/1.1' -+ count = 3 -+ exp_resumed = 'Resumed' -+ xargs = ['--sessionid', '--tls-max', tls_max, f'--tlsv{tls_max}'] -+ if env.curl_uses_lib('libressl'): -+ if tls_max == '1.3': -+ exp_resumed = 'Initial' # 1.2 works in LibreSSL, but 1.3 does not, TODO -+ if env.curl_uses_lib('rustls-ffi'): -+ exp_resumed = 'Initial' # Rustls does not support sessions, TODO -+ if env.curl_uses_lib('bearssl') and tls_max == '1.3': -+ pytest.skip('BearSSL does not support TLSv1.3') -+ if env.curl_uses_lib('mbedtls') and tls_max == '1.3' and \ -+ not env.curl_lib_version_at_least('mbedtls', '3.6.0'): -+ pytest.skip('mbedtls TLSv1.3 session resume not working in 3.6.0') -+ -+ run_env = os.environ.copy() -+ run_env['CURL_DEBUG'] = 'ssl' -+ curl = CurlClient(env=env, run_env=run_env) -+ # tell the server to close the connection after each request -+ urln = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo?'\ -+ f'id=[0-{count-1}]&close' -+ r = curl.http_download(urls=[urln], alpn_proto=proto, with_stats=True, -+ extra_args=xargs) -+ r.check_response(count=count, http_status=200) -+ # should have used one connection for each request, sessions after -+ # first should have been resumed -+ assert r.total_connects == count, r.dump_logs() -+ for i in range(count): -+ dfile = curl.download_file(i) -+ assert os.path.exists(dfile) -+ with open(dfile) as f: -+ djson = json.load(f) -+ assert djson['HTTPS'] == 'on', f'{i}: {djson}' -+ if i == 0: -+ assert djson['SSL_SESSION_RESUMED'] == 'Initial', f'{i}: {djson}\n{r.dump_logs()}' -+ else: -+ assert djson['SSL_SESSION_RESUMED'] == exp_resumed, f'{i}: {djson}\n{r.dump_logs()}' -+ -+ # use host name with trailing dot, verify handshake -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_03_trailing_dot(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = f'{env.domain1}.' -+ url = f'https://{env.authority_for(domain, proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto) -+ assert r.exit_code == 0, f'{r}' -+ assert r.json, f'{r}' -+ if proto != 'h3': # we proxy h3 -+ # the SNI the server received is without trailing dot -+ assert r.json['SSL_TLS_SNI'] == env.domain1, f'{r.json}' -+ -+ # use host name with double trailing dot, verify handshake -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_04_double_dot(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = f'{env.domain1}..' -+ url = f'https://{env.authority_for(domain, proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=[ -+ '-H', f'Host: {env.domain1}', -+ ]) -+ if r.exit_code == 0: -+ assert r.json, f'{r.stdout}' -+ # the SNI the server received is without trailing dot -+ if proto != 'h3': # we proxy h3 -+ assert r.json['SSL_TLS_SNI'] == env.domain1, f'{r.json}' -+ assert False, f'should not have succeeded: {r.json}' -+ # 7 - Rustls rejects a servername with .. during setup -+ # 35 - LibreSSL rejects setting an SNI name with trailing dot -+ # 60 - peer name matching failed against certificate -+ assert r.exit_code in [7, 35, 60], f'{r}' -+ -+ # use ip address for connect -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_05_ip_addr(self, env: Env, proto): -+ if env.curl_uses_lib('bearssl'): -+ pytest.skip("BearSSL does not support cert verification with IP addresses") -+ if env.curl_uses_lib('mbedtls'): -+ pytest.skip("mbedTLS does use IP addresses in SNI") -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = '127.0.0.1' -+ url = f'https://{env.authority_for(domain, proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto) -+ assert r.exit_code == 0, f'{r}' -+ assert r.json, f'{r}' -+ if proto != 'h3': # we proxy h3 -+ # the SNI should not have been used -+ assert 'SSL_TLS_SNI' not in r.json, f'{r.json}' -+ -+ # use localhost for connect -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_06_localhost(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = 'localhost' -+ url = f'https://{env.authority_for(domain, proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto) -+ assert r.exit_code == 0, f'{r}' -+ assert r.json, f'{r}' -+ if proto != 'h3': # we proxy h3 -+ assert r.json['SSL_TLS_SNI'] == domain, f'{r.json}' -+ -+ @staticmethod -+ def gen_test_17_07_list(): -+ tls13_tests = [ -+ [None, True], -+ [['TLS_AES_128_GCM_SHA256'], True], -+ [['TLS_AES_256_GCM_SHA384'], False], -+ [['TLS_CHACHA20_POLY1305_SHA256'], True], -+ [['TLS_AES_256_GCM_SHA384', -+ 'TLS_CHACHA20_POLY1305_SHA256'], True], -+ ] -+ tls12_tests = [ -+ [None, True], -+ [['ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256'], True], -+ [['ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384'], False], -+ [['ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305'], True], -+ [['ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', -+ 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305'], True], -+ ] -+ ret = [] -+ for tls_proto in ['TLSv1.3 +TLSv1.2', 'TLSv1.3', 'TLSv1.2']: -+ for [ciphers13, succeed13] in tls13_tests: -+ for [ciphers12, succeed12] in tls12_tests: -+ ret.append([tls_proto, ciphers13, ciphers12, succeed13, succeed12]) -+ return ret -+ -+ @pytest.mark.parametrize("tls_proto, ciphers13, ciphers12, succeed13, succeed12", gen_test_17_07_list()) -+ def test_17_07_ssl_ciphers(self, env: Env, httpd, tls_proto, ciphers13, ciphers12, succeed13, succeed12): -+ # to test setting cipher suites, the AES 256 ciphers are disabled in the test server -+ httpd.set_extra_config('base', [ -+ 'SSLCipherSuite SSL' -+ ' ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256' -+ ':ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305', -+ 'SSLCipherSuite TLSv1.3' -+ ' TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256', -+ f'SSLProtocol {tls_proto}' -+ ]) -+ httpd.reload_if_config_changed() -+ proto = 'http/1.1' -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo' -+ # SSL backend specifics -+ if env.curl_uses_lib('gnutls'): -+ pytest.skip('GnuTLS does not support setting ciphers') -+ elif env.curl_uses_lib('boringssl'): -+ if ciphers13 is not None: -+ pytest.skip('BoringSSL does not support setting TLSv1.3 ciphers') -+ elif env.curl_uses_lib('schannel'): # not in CI, so untested -+ if ciphers12 is not None: -+ pytest.skip('Schannel does not support setting TLSv1.2 ciphers by name') -+ elif env.curl_uses_lib('bearssl'): -+ if tls_proto == 'TLSv1.3': -+ pytest.skip('BearSSL does not support TLSv1.3') -+ tls_proto = 'TLSv1.2' -+ elif env.curl_uses_lib('mbedtls') and not env.curl_lib_version_at_least('mbedtls', '3.6.0'): -+ if tls_proto == 'TLSv1.3': -+ pytest.skip('mbedTLS < 3.6.0 does not support TLSv1.3') -+ elif env.curl_uses_lib('sectransp'): # not in CI, so untested -+ if tls_proto == 'TLSv1.3': -+ pytest.skip('Secure Transport does not support TLSv1.3') -+ tls_proto = 'TLSv1.2' -+ # test -+ extra_args = ['--tls13-ciphers', ':'.join(ciphers13)] if ciphers13 else [] -+ extra_args += ['--ciphers', ':'.join(ciphers12)] if ciphers12 else [] -+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=extra_args) -+ if tls_proto != 'TLSv1.2' and succeed13: -+ assert r.exit_code == 0, r.dump_logs() -+ assert r.json['HTTPS'] == 'on', r.dump_logs() -+ assert r.json['SSL_PROTOCOL'] == 'TLSv1.3', r.dump_logs() -+ assert ciphers13 is None or r.json['SSL_CIPHER'] in ciphers13, r.dump_logs() -+ elif tls_proto == 'TLSv1.2' and succeed12: -+ assert r.exit_code == 0, r.dump_logs() -+ assert r.json['HTTPS'] == 'on', r.dump_logs() -+ assert r.json['SSL_PROTOCOL'] == 'TLSv1.2', r.dump_logs() -+ assert ciphers12 is None or r.json['SSL_CIPHER'] in ciphers12, r.dump_logs() -+ else: -+ assert r.exit_code != 0, r.dump_logs() -+ -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_08_cert_status(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if not env.curl_uses_lib('openssl') and \ -+ not env.curl_uses_lib('gnutls') and \ -+ not env.curl_uses_lib('quictls'): -+ pytest.skip("TLS library does not support --cert-status") -+ curl = CurlClient(env=env) -+ domain = 'localhost' -+ url = f'https://{env.authority_for(domain, proto)}/' -+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=[ -+ '--cert-status' -+ ]) -+ # CURLE_SSL_INVALIDCERTSTATUS, our certs have no OCSP info -+ assert r.exit_code == 91, f'{r}' -+ -+ @staticmethod -+ def gen_test_17_09_list(): -+ return [[tls_proto, max_ver, min_ver] -+ for tls_proto in ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] -+ for max_ver in range(5) -+ for min_ver in range(-2, 4)] -+ -+ @pytest.mark.parametrize("tls_proto, max_ver, min_ver", gen_test_17_09_list()) -+ def test_17_09_ssl_min_max(self, env: Env, httpd, tls_proto, max_ver, min_ver): -+ httpd.set_extra_config('base', [ -+ f'SSLProtocol {tls_proto}', -+ 'SSLCipherSuite ALL:@SECLEVEL=0', -+ ]) -+ httpd.reload_if_config_changed() -+ proto = 'http/1.1' -+ run_env = os.environ.copy() -+ if env.curl_uses_lib('gnutls'): -+ # we need to override any default system configuration since -+ # we want to test all protocol versions. Ubuntu (or the GH image) -+ # disable TSL1.0 and TLS1.1 system wide. We do not want. -+ our_config = os.path.join(env.gen_dir, 'gnutls_config') -+ if not os.path.exists(our_config): -+ with open(our_config, 'w') as fd: -+ fd.write('# empty\n') -+ run_env['GNUTLS_SYSTEM_PRIORITY_FILE'] = our_config -+ curl = CurlClient(env=env, run_env=run_env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/sslinfo' -+ # SSL backend specifics -+ if env.curl_uses_lib('bearssl'): -+ supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', None] -+ elif env.curl_uses_lib('sectransp'): # not in CI, so untested -+ supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', None] -+ elif env.curl_uses_lib('gnutls'): -+ supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] -+ elif env.curl_uses_lib('quiche'): -+ supported = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] -+ else: # most SSL backends dropped support for TLSv1.0, TLSv1.1 -+ supported = [None, None, 'TLSv1.2', 'TLSv1.3'] -+ # test -+ extra_args = [[], ['--tlsv1'], ['--tlsv1.0'], ['--tlsv1.1'], ['--tlsv1.2'], ['--tlsv1.3']][min_ver+2] + \ -+ [['--tls-max', '1.0'], ['--tls-max', '1.1'], ['--tls-max', '1.2'], ['--tls-max', '1.3'], []][max_ver] -+ extra_args.extend(['--trace-config', 'ssl']) -+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=extra_args) -+ if max_ver >= min_ver and tls_proto in supported[max(0, min_ver):min(max_ver, 3)+1]: -+ assert r.exit_code == 0, f'extra_args={extra_args}\n{r.dump_logs()}' -+ assert r.json['HTTPS'] == 'on', r.dump_logs() -+ assert r.json['SSL_PROTOCOL'] == tls_proto, r.dump_logs() -+ else: -+ assert r.exit_code != 0, f'extra_args={extra_args}\n{r.dump_logs()}' -+ -+ def test_17_10_h3_session_reuse(self, env: Env, httpd, nghttpx): -+ if not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if not env.curl_uses_lib('quictls') and \ -+ not env.curl_uses_lib('gnutls') and \ -+ not env.curl_uses_lib('wolfssl'): -+ pytest.skip("QUIC session reuse not implemented") -+ count = 2 -+ docname = 'data-10k' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', -+ '-f', # forbid reuse of connections -+ '-r', f'{env.domain1}:{env.port_for("h3")}:127.0.0.1', -+ '-V', 'h3', url -+ ]) -+ r.check_exit_code(0) -+ # check that TLS session was reused as expected -+ reused_session = False -+ for line in r.trace_lines: -+ m = re.match(r'\[1-1] \* SSL reusing session.*', line) -+ if m: -+ reused_session = True -+ assert reused_session, f'{r}\n{r.dump_logs()}' -+ -+ # use host name server has no certificate for -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_11_wrong_host(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = f'insecure.{env.tld}' -+ url = f'https://{domain}:{env.port_for(proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto) -+ assert r.exit_code == 60, f'{r}' -+ -+ # use host name server has no cert for with --insecure -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_17_12_insecure(self, env: Env, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ curl = CurlClient(env=env) -+ domain = f'insecure.{env.tld}' -+ url = f'https://{domain}:{env.port_for(proto)}/curltest/sslinfo' -+ r = curl.http_get(url=url, alpn_proto=proto, extra_args=[ -+ '--insecure' -+ ]) -+ assert r.exit_code == 0, f'{r}' -+ assert r.json, f'{r}' -diff --git a/tests/http/test_18_methods.py b/tests/http/test_18_methods.py -new file mode 100644 -index 000000000..f9399db4b ---- /dev/null -+++ b/tests/http/test_18_methods.py -@@ -0,0 +1,71 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 logging -+import pytest -+ -+from testenv import Env, CurlClient -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+class TestMethods: -+ -+ @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_if_config_changed() -+ 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 1 file -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3']) -+ def test_18_01_delete(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ count = 1 -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/tweak?id=[0-{count-1}]' -+ r = curl.http_delete(urls=[url], alpn_proto=proto) -+ r.check_stats(count=count, http_status=204, exitcode=0) -+ -+ # make HTTP/2 in the server send -+ # - HEADER frame with 204 and eos=0 -+ # - 10ms later DATA frame length=0 and eos=1 -+ # should be accepted -+ def test_18_02_delete_h2_special(self, env: Env, httpd, nghttpx, repeat): -+ proto = 'h2' -+ count = 1 -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/tweak?id=[0-{count-1}]'\ -+ '&chunks=1&chunk_size=0&chunk_delay=10ms' -+ r = curl.http_delete(urls=[url], alpn_proto=proto) -+ r.check_stats(count=count, http_status=204, exitcode=0) -diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py -new file mode 100644 -index 000000000..bbb67d360 ---- /dev/null -+++ b/tests/http/test_19_shutdown.py -@@ -0,0 +1,175 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 logging -+import re -+import pytest -+ -+from testenv import Env, CurlClient, LocalClient -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+class TestShutdown: -+ -+ @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) -+ -+ # check with `tcpdump` that we see curl TCP RST packets -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ @pytest.mark.parametrize("proto", ['http/1.1']) -+ def test_19_01_check_tcp_rst(self, env: Env, httpd, repeat, proto): -+ if env.ci_run: -+ pytest.skip("seems not to work in CI") -+ curl = CurlClient(env=env) -+ url = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-1]' -+ r = curl.http_download(urls=[url], alpn_proto=proto, with_tcpdump=True, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_response(http_status=200, count=2) -+ assert r.tcpdump -+ assert len(r.tcpdump.stats) != 0, f'Expected TCP RSTs packets: {r.tcpdump.stderr}' -+ -+ # check with `tcpdump` that we do NOT see TCP RST when CURL_GRACEFUL_SHUTDOWN set -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ @pytest.mark.parametrize("proto", ['http/1.1', 'h2']) -+ def test_19_02_check_shutdown(self, env: Env, httpd, repeat, proto): -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ curl = CurlClient(env=env, run_env={ -+ 'CURL_GRACEFUL_SHUTDOWN': '2000', -+ 'CURL_DEBUG': 'ssl,tcp' -+ }) -+ url = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-1]' -+ r = curl.http_download(urls=[url], alpn_proto=proto, with_tcpdump=True, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_response(http_status=200, count=2) -+ assert r.tcpdump -+ assert len(r.tcpdump.stats) == 0, 'Unexpected TCP RSTs packets' -+ -+ # run downloads where the server closes the connection after each request -+ @pytest.mark.parametrize("proto", ['http/1.1']) -+ def test_19_03_shutdown_by_server(self, env: Env, httpd, repeat, proto): -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ count = 10 -+ curl = CurlClient(env=env, run_env={ -+ 'CURL_GRACEFUL_SHUTDOWN': '2000', -+ 'CURL_DEBUG': 'ssl' -+ }) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/tweak/?'\ -+ f'id=[0-{count-1}]&with_cl&close' -+ r = curl.http_download(urls=[url], alpn_proto=proto) -+ r.check_response(http_status=200, count=count) -+ shutdowns = [line for line in r.trace_lines -+ if re.match(r'.*CCACHE\] shutdown #\d+, done=1', line)] -+ assert len(shutdowns) == count, f'{shutdowns}' -+ -+ # run downloads with CURLOPT_FORBID_REUSE set, meaning *we* close -+ # the connection after each request -+ @pytest.mark.parametrize("proto", ['http/1.1']) -+ def test_19_04_shutdown_by_curl(self, env: Env, httpd, proto, repeat): -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ count = 10 -+ docname = 'data.json' -+ url = f'https://localhost:{env.https_port}/{docname}' -+ client = LocalClient(name='hx-download', env=env, run_env={ -+ 'CURL_GRACEFUL_SHUTDOWN': '2000', -+ 'CURL_DEBUG': 'ssl' -+ }) -+ if not client.exists(): -+ pytest.skip(f'example client not built: {client.name}') -+ r = client.run(args=[ -+ '-n', f'{count}', '-f', '-V', proto, url -+ ]) -+ r.check_exit_code(0) -+ shutdowns = [line for line in r.trace_lines -+ if re.match(r'.*CCACHE\] shutdown #\d+, done=1', line)] -+ assert len(shutdowns) == count, f'{shutdowns}' -+ -+ # run event-based downloads with CURLOPT_FORBID_REUSE set, meaning *we* close -+ # the connection after each request -+ @pytest.mark.parametrize("proto", ['http/1.1']) -+ def test_19_05_event_shutdown_by_server(self, env: Env, httpd, proto, repeat): -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ count = 10 -+ curl = CurlClient(env=env, run_env={ -+ # forbid connection reuse to trigger shutdowns after transfer -+ 'CURL_FORBID_REUSE': '1', -+ # make socket receives block 50% of the time to delay shutdown -+ 'CURL_DBG_SOCK_RBLOCK': '50', -+ 'CURL_DEBUG': 'ssl' -+ }) -+ url = f'https://{env.authority_for(env.domain1, proto)}/curltest/tweak/?'\ -+ f'id=[0-{count-1}]&with_cl&' -+ r = curl.http_download(urls=[url], alpn_proto=proto, extra_args=[ -+ '--test-event' -+ ]) -+ r.check_response(http_status=200, count=count) -+ # check that we closed all connections -+ closings = [line for line in r.trace_lines -+ if re.match(r'.*CCACHE\] closing #\d+', line)] -+ assert len(closings) == count, f'{closings}' -+ # check that all connection sockets were removed from event -+ removes = [line for line in r.trace_lines -+ if re.match(r'.*socket cb: socket \d+ REMOVED', line)] -+ assert len(removes) == count, f'{removes}' -+ -+ # check graceful shutdown on multiplexed http -+ @pytest.mark.parametrize("proto", ['h2', 'h3']) -+ def test_19_06_check_shutdown(self, env: Env, httpd, nghttpx, repeat, proto): -+ if proto == 'h3' and not env.have_h3(): -+ pytest.skip("h3 not supported") -+ if not env.curl_is_debug(): -+ pytest.skip('only works for curl debug builds') -+ curl = CurlClient(env=env, run_env={ -+ 'CURL_GRACEFUL_SHUTDOWN': '2000', -+ 'CURL_DEBUG': 'all' -+ }) -+ url = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-1]' -+ r = curl.http_download(urls=[url], alpn_proto=proto, with_tcpdump=True, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_response(http_status=200, count=2) -+ # check connection cache closings -+ shutdowns = [line for line in r.trace_lines -+ if re.match(r'.*CCACHE\] shutdown #\d+, done=1', line)] -+ assert len(shutdowns) == 1, f'{shutdowns}' -diff --git a/tests/http/test_30_vsftpd.py b/tests/http/test_30_vsftpd.py -new file mode 100644 -index 000000000..238184c2a ---- /dev/null -+++ b/tests/http/test_30_vsftpd.py -@@ -0,0 +1,216 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+import shutil -+import pytest -+ -+from testenv import Env, CurlClient, VsFTPD -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+@pytest.mark.skipif(condition=not Env.has_vsftpd(), reason="missing vsftpd") -+class TestVsFTPD: -+ -+ @pytest.fixture(autouse=True, scope='class') -+ def vsftpd(self, env): -+ vsftpd = VsFTPD(env=env) -+ assert vsftpd.start() -+ yield vsftpd -+ vsftpd.stop() -+ -+ def _make_docs_file(self, docs_dir: str, fname: str, fsize: int): -+ fpath = os.path.join(docs_dir, fname) -+ data1k = 1024*'x' -+ flen = 0 -+ with open(fpath, 'w') as fd: -+ while flen < fsize: -+ fd.write(data1k) -+ flen += len(data1k) -+ return flen -+ -+ @pytest.fixture(autouse=True, scope='class') -+ def _class_scope(self, env, vsftpd): -+ if os.path.exists(vsftpd.docs_dir): -+ shutil.rmtree(vsftpd.docs_dir) -+ if not os.path.exists(vsftpd.docs_dir): -+ os.makedirs(vsftpd.docs_dir) -+ self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-1k', fsize=1024) -+ self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-10k', fsize=10*1024) -+ self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-1m', fsize=1024*1024) -+ self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-10m', fsize=10*1024*1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-1k", fsize=1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-100k", fsize=100*1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-1m", fsize=1024*1024) -+ -+ def test_30_01_list_dir(self, env: Env, vsftpd: VsFTPD, repeat): -+ curl = CurlClient(env=env) -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/' -+ r = curl.ftp_get(urls=[url], with_stats=True) -+ r.check_stats(count=1, http_status=226) -+ lines = open(os.path.join(curl.run_dir, 'download_#1.data')).readlines() -+ assert len(lines) == 4, f'list: {lines}' -+ -+ # download 1 file, no SSL -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_30_02_download_1(self, env: Env, vsftpd: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpd.docs_dir, f'{docname}') -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_get(urls=[url], with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_30_03_download_10_serial(self, env: Env, vsftpd: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpd.docs_dir, f'{docname}') -+ count = 10 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_get(urls=[url], with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_30_04_download_10_parallel(self, env: Env, vsftpd: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpd.docs_dir, f'{docname}') -+ count = 10 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_get(urls=[url], with_stats=True, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'upload-1k', 'upload-100k', 'upload-1m' -+ ]) -+ def test_30_05_upload_1(self, env: Env, vsftpd: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpd.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/' -+ r = curl.ftp_upload(urls=[url], fupload=f'{srcfile}', with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_upload(env, vsftpd, docname=docname) -+ -+ def _rmf(self, path): -+ if os.path.exists(path): -+ return os.remove(path) -+ -+ # check with `tcpdump` if curl causes any TCP RST packets -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ def test_30_06_shutdownh_download(self, env: Env, vsftpd: VsFTPD, repeat): -+ docname = 'data-1k' -+ curl = CurlClient(env=env) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_get(urls=[url], with_stats=True, with_tcpdump=True) -+ r.check_stats(count=count, http_status=226) -+ assert r.tcpdump -+ assert len(r.tcpdump.stats) == 0, 'Unexpected TCP RSTs packets' -+ -+ # check with `tcpdump` if curl causes any TCP RST packets -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ def test_30_07_shutdownh_upload(self, env: Env, vsftpd: VsFTPD, repeat): -+ docname = 'upload-1k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpd.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/' -+ r = curl.ftp_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, with_tcpdump=True) -+ r.check_stats(count=count, http_status=226) -+ assert r.tcpdump -+ assert len(r.tcpdump.stats) == 0, 'Unexpected TCP RSTs packets' -+ -+ def test_30_08_active_download(self, env: Env, vsftpd: VsFTPD): -+ docname = 'data-10k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpd.docs_dir, f'{docname}') -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_get(urls=[url], with_stats=True, extra_args=[ -+ '--ftp-port', '127.0.0.1' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ def test_30_09_active_upload(self, env: Env, vsftpd: VsFTPD): -+ docname = 'upload-1k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpd.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpd.port}/' -+ r = curl.ftp_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, extra_args=[ -+ '--ftp-port', '127.0.0.1' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_upload(env, vsftpd, docname=docname) -+ -+ def check_downloads(self, client, srcfile: str, count: int, -+ complete: bool = True): -+ for i in range(count): -+ dfile = client.download_file(i) -+ assert os.path.exists(dfile) -+ if complete and not filecmp.cmp(srcfile, dfile, shallow=False): -+ diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), -+ b=open(dfile).readlines(), -+ fromfile=srcfile, -+ tofile=dfile, -+ n=1)) -+ assert False, f'download {dfile} differs:\n{diff}' -+ -+ def check_upload(self, env, vsftpd: VsFTPD, docname): -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpd.docs_dir, docname) -+ assert os.path.exists(srcfile) -+ assert os.path.exists(dstfile) -+ if not filecmp.cmp(srcfile, dstfile, shallow=False): -+ diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), -+ b=open(dstfile).readlines(), -+ fromfile=srcfile, -+ tofile=dstfile, -+ n=1)) -+ assert False, f'upload {dstfile} differs:\n{diff}' -diff --git a/tests/http/test_31_vsftpds.py b/tests/http/test_31_vsftpds.py -new file mode 100644 -index 000000000..4c7b223ec ---- /dev/null -+++ b/tests/http/test_31_vsftpds.py -@@ -0,0 +1,264 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 -+import shutil -+import pytest -+ -+from testenv import Env, CurlClient, VsFTPD -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+@pytest.mark.skipif(condition=not Env.has_vsftpd(), reason="missing vsftpd") -+class TestVsFTPD: -+ -+ SUPPORTS_SSL = True -+ -+ @pytest.fixture(autouse=True, scope='class') -+ def vsftpds(self, env): -+ if not TestVsFTPD.SUPPORTS_SSL: -+ pytest.skip('vsftpd does not seem to support SSL') -+ vsftpds = VsFTPD(env=env, with_ssl=True) -+ if not vsftpds.start(): -+ vsftpds.stop() -+ TestVsFTPD.SUPPORTS_SSL = False -+ pytest.skip('vsftpd does not seem to support SSL') -+ yield vsftpds -+ vsftpds.stop() -+ -+ def _make_docs_file(self, docs_dir: str, fname: str, fsize: int): -+ fpath = os.path.join(docs_dir, fname) -+ data1k = 1024*'x' -+ flen = 0 -+ with open(fpath, 'w') as fd: -+ while flen < fsize: -+ fd.write(data1k) -+ flen += len(data1k) -+ return flen -+ -+ @pytest.fixture(autouse=True, scope='class') -+ def _class_scope(self, env, vsftpds): -+ if os.path.exists(vsftpds.docs_dir): -+ shutil.rmtree(vsftpds.docs_dir) -+ if not os.path.exists(vsftpds.docs_dir): -+ os.makedirs(vsftpds.docs_dir) -+ self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-1k', fsize=1024) -+ self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-10k', fsize=10*1024) -+ self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-1m', fsize=1024*1024) -+ self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-10m', fsize=10*1024*1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-1k", fsize=1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-100k", fsize=100*1024) -+ env.make_data_file(indir=env.gen_dir, fname="upload-1m", fsize=1024*1024) -+ -+ def test_31_01_list_dir(self, env: Env, vsftpds: VsFTPD, repeat): -+ curl = CurlClient(env=env) -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True) -+ r.check_stats(count=1, http_status=226) -+ lines = open(os.path.join(curl.run_dir, 'download_#1.data')).readlines() -+ assert len(lines) == 4, f'list: {lines}' -+ -+ # download 1 file, no SSL -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_31_02_download_1(self, env: Env, vsftpds: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpds.docs_dir, f'{docname}') -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_31_03_download_10_serial(self, env: Env, vsftpds: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpds.docs_dir, f'{docname}') -+ count = 10 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'data-1k', 'data-1m', 'data-10m' -+ ]) -+ def test_31_04_download_10_parallel(self, env: Env, vsftpds: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpds.docs_dir, f'{docname}') -+ count = 10 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True, extra_args=[ -+ '--parallel' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ @pytest.mark.parametrize("docname", [ -+ 'upload-1k', 'upload-100k', 'upload-1m' -+ ]) -+ def test_31_05_upload_1(self, env: Env, vsftpds: VsFTPD, docname, repeat): -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpds.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/' -+ r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ self.check_upload(env, vsftpds, docname=docname) -+ -+ def _rmf(self, path): -+ if os.path.exists(path): -+ return os.remove(path) -+ -+ # check with `tcpdump` if curl causes any TCP RST packets -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ def test_31_06_shutdownh_download(self, env: Env, vsftpds: VsFTPD, repeat): -+ docname = 'data-1k' -+ curl = CurlClient(env=env) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True, with_tcpdump=True) -+ r.check_stats(count=count, http_status=226) -+ # vsftp closes control connection without niceties, -+ # disregard RST packets it sent from its port to curl -+ assert len(r.tcpdump.stats_excluding(src_port=env.ftps_port)) == 0, 'Unexpected TCP RSTs packets' -+ -+ # check with `tcpdump` if curl causes any TCP RST packets -+ @pytest.mark.skipif(condition=not Env.tcpdump(), reason="tcpdump not available") -+ def test_31_07_shutdownh_upload(self, env: Env, vsftpds: VsFTPD, repeat): -+ docname = 'upload-1k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpds.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/' -+ r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, with_tcpdump=True) -+ r.check_stats(count=count, http_status=226) -+ # vsftp closes control connection without niceties, -+ # disregard RST packets it sent from its port to curl -+ assert len(r.tcpdump.stats_excluding(src_port=env.ftps_port)) == 0, 'Unexpected TCP RSTs packets' -+ -+ def test_31_08_upload_ascii(self, env: Env, vsftpds: VsFTPD): -+ docname = 'upload-ascii' -+ line_length = 21 -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpds.docs_dir, docname) -+ env.make_data_file(indir=env.gen_dir, fname=docname, fsize=100*1024, -+ line_length=line_length) -+ srcsize = os.path.getsize(srcfile) -+ self._rmf(dstfile) -+ count = 1 -+ curl = CurlClient(env=env) -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/' -+ r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, -+ extra_args=['--use-ascii']) -+ r.check_stats(count=count, http_status=226) -+ # expect the uploaded file to be number of converted newlines larger -+ dstsize = os.path.getsize(dstfile) -+ newlines = len(open(srcfile).readlines()) -+ assert (srcsize + newlines) == dstsize, \ -+ f'expected source with {newlines} lines to be that much larger,'\ -+ f'instead srcsize={srcsize}, upload size={dstsize}, diff={dstsize-srcsize}' -+ -+ def test_31_08_active_download(self, env: Env, vsftpds: VsFTPD): -+ docname = 'data-10k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(vsftpds.docs_dir, f'{docname}') -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}?[0-{count-1}]' -+ r = curl.ftp_ssl_get(urls=[url], with_stats=True, extra_args=[ -+ '--ftp-port', '127.0.0.1' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_downloads(curl, srcfile, count) -+ -+ def test_31_09_active_upload(self, env: Env, vsftpds: VsFTPD): -+ docname = 'upload-1k' -+ curl = CurlClient(env=env) -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpds.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/' -+ r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True, extra_args=[ -+ '--ftp-port', '127.0.0.1' -+ ]) -+ r.check_stats(count=count, http_status=226) -+ self.check_upload(env, vsftpds, docname=docname) -+ -+ @pytest.mark.parametrize("indata", [ -+ '1234567890', '' -+ ]) -+ def test_31_10_upload_stdin(self, env: Env, vsftpds: VsFTPD, indata): -+ curl = CurlClient(env=env) -+ docname = "upload_31_10" -+ dstfile = os.path.join(vsftpds.docs_dir, docname) -+ self._rmf(dstfile) -+ count = 1 -+ url = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}' -+ r = curl.ftp_ssl_upload(urls=[url], updata=indata, with_stats=True) -+ r.check_stats(count=count, http_status=226) -+ assert os.path.exists(dstfile) -+ destdata = open(dstfile).readlines() -+ expdata = [indata] if len(indata) else [] -+ assert expdata == destdata, f'exected: {expdata}, got: {destdata}' -+ -+ def check_downloads(self, client, srcfile: str, count: int, -+ complete: bool = True): -+ for i in range(count): -+ dfile = client.download_file(i) -+ assert os.path.exists(dfile) -+ if complete and not filecmp.cmp(srcfile, dfile, shallow=False): -+ diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), -+ b=open(dfile).readlines(), -+ fromfile=srcfile, -+ tofile=dfile, -+ n=1)) -+ assert False, f'download {dfile} differs:\n{diff}' -+ -+ def check_upload(self, env, vsftpd: VsFTPD, docname): -+ srcfile = os.path.join(env.gen_dir, docname) -+ dstfile = os.path.join(vsftpd.docs_dir, docname) -+ assert os.path.exists(srcfile) -+ assert os.path.exists(dstfile) -+ if not filecmp.cmp(srcfile, dstfile, shallow=False): -+ diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(), -+ b=open(dstfile).readlines(), -+ fromfile=srcfile, -+ tofile=dstfile, -+ n=1)) -+ assert False, f'upload {dstfile} differs:\n{diff}' -diff --git a/tests/http/testenv/__init__.py b/tests/http/testenv/__init__.py -index c4c032028..539af2aad 100644 ---- a/tests/http/testenv/__init__.py -+++ b/tests/http/testenv/__init__.py -@@ -23,7 +23,7 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --# -+# ruff: noqa: F401, E402 - import pytest - pytest.register_assert_rewrite("testenv.env", "testenv.curl", "testenv.caddy", - "testenv.httpd", "testenv.nghttpx") -@@ -34,5 +34,5 @@ from .caddy import Caddy - from .httpd import Httpd - from .curl import CurlClient, ExecResult, RunProfile - from .client import LocalClient --from .nghttpx import Nghttpx - from .nghttpx import Nghttpx, NghttpxQuic, NghttpxFwd -+from .vsftpd import VsFTPD -diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py -index ea1343a95..748ef3d5f 100644 ---- a/tests/http/testenv/caddy.py -+++ b/tests/http/testenv/caddy.py -@@ -56,7 +56,7 @@ class Caddy: - return self._docs_dir - - @property -- def port(self) -> str: -+ def port(self) -> int: - return self.env.caddy_https_port - - def clear_logs(self): -@@ -141,6 +141,10 @@ class Caddy: - def _write_config(self): - domain1 = self.env.domain1 - creds1 = self.env.get_credentials(domain1) -+ assert creds1 # convince pytype this isn't None -+ domain2 = self.env.domain2 -+ creds2 = self.env.get_credentials(domain2) -+ assert creds2 # convince pytype this isn't None - self._mkpath(self._docs_dir) - self._mkpath(self._tmp_dir) - with open(os.path.join(self._docs_dir, 'data.json'), 'w') as fd: -@@ -150,18 +154,23 @@ class Caddy: - fd.write(JSONEncoder().encode(data)) - with open(self._conf_file, 'w') as fd: - conf = [ # base server config -- f'{{', -+ '{', - f' http_port {self.env.caddy_http_port}', - f' https_port {self.env.caddy_https_port}', - f' servers :{self.env.caddy_https_port} {{', -- f' protocols h3 h2 h1', -- f' }}', -- f'}}', -+ ' protocols h3 h2 h1', -+ ' }', -+ '}', - f'{domain1}:{self.env.caddy_https_port} {{', -- f' file_server * {{', -+ ' file_server * {', - f' root {self._docs_dir}', -- f' }}', -+ ' }', - f' tls {creds1.cert_file} {creds1.pkey_file}', -- f'}}', -+ '}', -+ f'{domain2} {{', -+ f' reverse_proxy /* http://localhost:{self.env.http_port} {{', -+ ' }', -+ f' tls {creds2.cert_file} {creds2.pkey_file}', -+ '}', - ] - fd.write("\n".join(conf)) -diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py -index cdbfed1fc..3795ba947 100644 ---- a/tests/http/testenv/certs.py -+++ b/tests/http/testenv/certs.py -@@ -27,7 +27,7 @@ - import ipaddress - import os - import re --from datetime import timedelta, datetime -+from datetime import timedelta, datetime, timezone - from typing import List, Any, Optional - - from cryptography import x509 -@@ -126,6 +126,7 @@ class Credentials: - self._cert_file = None - self._pkey_file = None - self._store = None -+ self._combined_file = None - - @property - def name(self) -> str: -@@ -315,10 +316,18 @@ class CertStore: - if os.path.isfile(cert_file) and os.path.isfile(pkey_file): - cert = self.load_pem_cert(cert_file) - pkey = self.load_pem_pkey(pkey_file) -- if check_valid and \ -- ((cert.not_valid_after < datetime.now()) or -- (cert.not_valid_before > datetime.now())): -- return None -+ try: -+ now = datetime.now(tz=timezone.utc) -+ if check_valid and \ -+ ((cert.not_valid_after_utc < now) or -+ (cert.not_valid_before_utc > now)): -+ return None -+ except AttributeError: # older python -+ now = datetime.now() -+ if check_valid and \ -+ ((cert.not_valid_after < now) or -+ (cert.not_valid_before > now)): -+ return None - creds = Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer) - creds.set_store(self) - creds.set_files(cert_file, pkey_file, comb_file) -@@ -344,7 +353,9 @@ class TestCA: - valid_from: timedelta = timedelta(days=-1), - valid_to: timedelta = timedelta(days=89), - ) -> Credentials: -- """Create a certificate signed by this CA for the given domains. -+ """ -+ Create a certificate signed by this CA for the given domains. -+ - :returns: the certificate and private key PEM file paths - """ - if spec.domains and len(spec.domains): -@@ -364,7 +375,7 @@ class TestCA: - return creds - - @staticmethod -- def _make_x509_name(org_name: str = None, common_name: str = None, parent: x509.Name = None) -> x509.Name: -+ def _make_x509_name(org_name: Optional[str] = None, common_name: Optional[str] = None, parent: x509.Name = None) -> x509.Name: - name_pieces = [] - if org_name: - oid = NameOID.ORGANIZATIONAL_UNIT_NAME if parent else NameOID.ORGANIZATION_NAME -@@ -372,7 +383,7 @@ class TestCA: - elif common_name: - name_pieces.append(x509.NameAttribute(NameOID.COMMON_NAME, common_name)) - if parent: -- name_pieces.extend([rdn for rdn in parent]) -+ name_pieces.extend(list(parent)) - return x509.Name(name_pieces) - - @staticmethod -@@ -380,8 +391,8 @@ class TestCA: - subject: x509.Name, - pkey: Any, - issuer_subject: Optional[Credentials], -- valid_from_delta: timedelta = None, -- valid_until_delta: timedelta = None -+ valid_from_delta: Optional[timedelta] = None, -+ valid_until_delta: Optional[timedelta] = None - ): - pubkey = pkey.public_key() - issuer_subject = issuer_subject if issuer_subject is not None else subject -@@ -439,7 +450,8 @@ class TestCA: - for name in domains: - try: - names.append(x509.IPAddress(ipaddress.ip_address(name))) -- except: -+ # TODO: specify specific exceptions here -+ except: # noqa: E722 - names.append(x509.DNSName(name)) - - return csr.add_extension( -@@ -460,7 +472,7 @@ class TestCA: - ) - - @staticmethod -- def _add_client_usages(csr: Any, issuer: Credentials, rfc82name: str = None) -> Any: -+ def _add_client_usages(csr: Any, issuer: Credentials, rfc82name: Optional[str] = None) -> Any: - cert = csr.add_extension( - x509.BasicConstraints(ca=False, path_length=None), - critical=True, -@@ -485,7 +497,7 @@ class TestCA: - - @staticmethod - def _make_ca_credentials(name, key_type: Any, -- issuer: Credentials = None, -+ issuer: Optional[Credentials] = None, - valid_from: timedelta = timedelta(days=-1), - valid_to: timedelta = timedelta(days=89), - ) -> Credentials: -@@ -512,7 +524,6 @@ class TestCA: - valid_from: timedelta = timedelta(days=-1), - valid_to: timedelta = timedelta(days=89), - ) -> Credentials: -- name = name - pkey = _private_key(key_type=key_type) - subject = TestCA._make_x509_name(common_name=name, parent=issuer.subject) - csr = TestCA._make_csr(subject=subject, -diff --git a/tests/http/testenv/client.py b/tests/http/testenv/client.py -index e8ffb040a..3981752ec 100644 ---- a/tests/http/testenv/client.py -+++ b/tests/http/testenv/client.py -@@ -24,16 +24,12 @@ - # - ########################################################################### - # --import pytest --import json - import logging - import os --import re - import shutil - import subprocess --from datetime import timedelta, datetime --from typing import List, Optional, Dict, Union --from urllib.parse import urlparse -+from datetime import datetime -+from typing import Optional, Dict - - from . import ExecResult - from .env import Env -@@ -48,9 +44,9 @@ class LocalClient: - timeout: Optional[float] = None, - run_env: Optional[Dict[str,str]] = None): - self.name = name -- self.path = os.path.join(env.project_dir, f'tests/http/clients/{name}') -+ self.path = os.path.join(env.build_dir, f'tests/http/clients/{name}') - self.env = env -- self._run_env= run_env -+ self._run_env = run_env - self._timeout = timeout if timeout else env.test_timeout - self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl - self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, name) -@@ -92,14 +88,19 @@ class LocalClient: - exception = None - myargs = [self.path] - myargs.extend(args) -+ run_env = None -+ if self._run_env: -+ run_env = self._run_env.copy() -+ for key in ['CURL_DEBUG']: -+ if key in os.environ and key not in run_env: -+ run_env[key] = os.environ[key] - try: -- with open(self._stdoutfile, 'w') as cout: -- with open(self._stderrfile, 'w') as cerr: -- p = subprocess.run(myargs, stderr=cerr, stdout=cout, -- cwd=self._run_dir, shell=False, -- input=None, env=self._run_env, -- timeout=self._timeout) -- exitcode = p.returncode -+ with open(self._stdoutfile, 'w') as cout, open(self._stderrfile, 'w') as cerr: -+ p = subprocess.run(myargs, stderr=cerr, stdout=cout, -+ cwd=self._run_dir, shell=False, -+ input=None, env=run_env, -+ timeout=self._timeout) -+ exitcode = p.returncode - except subprocess.TimeoutExpired: - log.warning(f'Timeout after {self._timeout}s: {args}') - exitcode = -1 -diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py -index bfd6fdefc..ee224d9a6 100644 ---- a/tests/http/testenv/curl.py -+++ b/tests/http/testenv/curl.py -@@ -27,6 +27,10 @@ - import json - import logging - import os -+import sys -+import time -+from threading import Thread -+ - import psutil - import re - import shutil -@@ -51,7 +55,8 @@ class RunProfile: - avg = {} - stats = [p.stats for p in profiles] - for key in cls.STAT_KEYS: -- avg[key] = mean([s[key] for s in stats]) -+ vals = [s[key] for s in stats] -+ avg[key] = mean(vals) if len(vals) else 0.0 - return avg - - def __init__(self, pid: int, started_at: datetime, run_dir): -@@ -103,6 +108,79 @@ class RunProfile: - f'stats={self.stats}]' - - -+class RunTcpDump: -+ -+ def __init__(self, env, run_dir): -+ self._env = env -+ self._run_dir = run_dir -+ self._proc = None -+ self._stdoutfile = os.path.join(self._run_dir, 'tcpdump.out') -+ self._stderrfile = os.path.join(self._run_dir, 'tcpdump.err') -+ -+ @property -+ def stats(self) -> Optional[List[str]]: -+ if self._proc: -+ raise Exception('tcpdump still running') -+ return [line -+ for line in open(self._stdoutfile) -+ if re.match(r'.* IP 127\.0\.0\.1\.\d+ [<>] 127\.0\.0\.1\.\d+:.*', line)] -+ -+ def stats_excluding(self, src_port) -> Optional[List[str]]: -+ if self._proc: -+ raise Exception('tcpdump still running') -+ return [line -+ for line in self.stats -+ if not re.match(r'.* IP 127\.0\.0\.1\.' + str(src_port) + ' >.*', line)] -+ -+ @property -+ def stderr(self) -> List[str]: -+ if self._proc: -+ raise Exception('tcpdump still running') -+ return open(self._stderrfile).readlines() -+ -+ def sample(self): -+ # not sure how to make that detection reliable for all platforms -+ local_if = 'lo0' if sys.platform.startswith('darwin') else 'lo' -+ try: -+ tcpdump = self._env.tcpdump() -+ if tcpdump is None: -+ raise Exception('tcpdump not available') -+ # look with tcpdump for TCP RST packets which indicate -+ # we did not shut down connections cleanly -+ args = [] -+ # at least on Linux, we need root permissions to run tcpdump -+ if sys.platform.startswith('linux'): -+ args.append('sudo') -+ args.extend([ -+ tcpdump, '-i', local_if, '-n', 'tcp[tcpflags] & (tcp-rst)!=0' -+ ]) -+ with open(self._stdoutfile, 'w') as cout, open(self._stderrfile, 'w') as cerr: -+ self._proc = subprocess.Popen(args, stdout=cout, stderr=cerr, -+ text=True, cwd=self._run_dir, -+ shell=False) -+ assert self._proc -+ assert self._proc.returncode is None -+ while self._proc: -+ try: -+ self._proc.wait(timeout=1) -+ except subprocess.TimeoutExpired: -+ pass -+ except Exception: -+ log.exception('Tcpdump') -+ -+ def start(self): -+ def do_sample(): -+ self.sample() -+ t = Thread(target=do_sample) -+ t.start() -+ -+ def finish(self): -+ if self._proc: -+ time.sleep(1) -+ self._proc.terminate() -+ self._proc = None -+ -+ - class ExecResult: - - def __init__(self, args: List[str], exit_code: int, -@@ -110,13 +188,15 @@ class ExecResult: - duration: Optional[timedelta] = None, - with_stats: bool = False, - exception: Optional[str] = None, -- profile: Optional[RunProfile] = None): -+ profile: Optional[RunProfile] = None, -+ tcpdump: Optional[RunTcpDump] = None): - self._args = args - self._exit_code = exit_code - self._exception = exception - self._stdout = stdout - self._stderr = stderr - self._profile = profile -+ self._tcpdump = tcpdump - self._duration = duration if duration is not None else timedelta() - self._response = None - self._responses = [] -@@ -132,7 +212,7 @@ class ExecResult: - try: - out = ''.join(self._stdout) - self._json_out = json.loads(out) -- except: -+ except: # noqa: E722 - pass - - def __repr__(self): -@@ -141,11 +221,12 @@ class ExecResult: - - def _parse_stats(self): - self._stats = [] -- for l in self._stdout: -+ for line in self._stdout: - try: -- self._stats.append(json.loads(l)) -- except: -- log.error(f'not a JSON stat: {l}') -+ self._stats.append(json.loads(line)) -+ # TODO: specify specific exceptions here -+ except: # noqa: E722 -+ log.exception(f'not a JSON stat: {line}') - break - - @property -@@ -185,6 +266,10 @@ class ExecResult: - def profile(self) -> Optional[RunProfile]: - return self._profile - -+ @property -+ def tcpdump(self) -> Optional[RunTcpDump]: -+ return self._tcpdump -+ - @property - def response(self) -> Optional[Dict]: - return self._response -@@ -301,7 +386,9 @@ class ExecResult: - f'were made\n{self.dump_logs()}' - - def check_stats(self, count: int, http_status: Optional[int] = None, -- exitcode: Optional[int] = None): -+ exitcode: Optional[int] = None, -+ remote_port: Optional[int] = None, -+ remote_ip: Optional[str] = None): - if exitcode is None: - self.check_exit_code(0) - assert len(self.stats) == count, \ -@@ -319,6 +406,18 @@ class ExecResult: - assert x['exitcode'] == exitcode, \ - f'status #{idx} exitcode: expected {exitcode}, '\ - f'got {x["exitcode"]}\n{self.dump_stat(x)}' -+ if remote_port is not None: -+ for idx, x in enumerate(self.stats): -+ assert 'remote_port' in x, f'remote_port missing\n{self.dump_stat(x)}' -+ assert x['remote_port'] == remote_port, \ -+ f'status #{idx} remote_port: expected {remote_port}, '\ -+ f'got {x["remote_port"]}\n{self.dump_stat(x)}' -+ if remote_ip is not None: -+ for idx, x in enumerate(self.stats): -+ assert 'remote_ip' in x, f'remote_ip missing\n{self.dump_stat(x)}' -+ assert x['remote_ip'] == remote_ip, \ -+ f'status #{idx} remote_ip: expected {remote_ip}, '\ -+ f'got {x["remote_ip"]}\n{self.dump_stat(x)}' - - def dump_logs(self): - lines = ['>>--stdout ----------------------------------------------\n'] -@@ -359,8 +458,12 @@ class CurlClient: - 'h3': '--http3-only', - } - -- def __init__(self, env: Env, run_dir: Optional[str] = None, -- timeout: Optional[float] = None, silent: bool = False): -+ def __init__(self, env: Env, -+ run_dir: Optional[str] = None, -+ timeout: Optional[float] = None, -+ silent: bool = False, -+ run_env: Optional[Dict[str, str]] = None, -+ server_addr: Optional[str] = None): - self.env = env - self._timeout = timeout if timeout else env.test_timeout - self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl -@@ -370,6 +473,8 @@ class CurlClient: - self._headerfile = f'{self._run_dir}/curl.headers' - self._log_path = f'{self._run_dir}/curl.log' - self._silent = silent -+ self._run_env = run_env -+ self._server_addr = server_addr if server_addr else '127.0.0.1' - self._rmrf(self._run_dir) - self._mkpath(self._run_dir) - -@@ -395,12 +500,12 @@ class CurlClient: - def get_proxy_args(self, proto: str = 'http/1.1', - proxys: bool = True, tunnel: bool = False, - use_ip: bool = False): -- proxy_name = '127.0.0.1' if use_ip else self.env.proxy_domain -+ proxy_name = self._server_addr if use_ip else self.env.proxy_domain - if proxys: - pport = self.env.pts_port(proto) if tunnel else self.env.proxys_port - xargs = [ - '--proxy', f'https://{proxy_name}:{pport}/', -- '--resolve', f'{proxy_name}:{pport}:127.0.0.1', -+ '--resolve', f'{proxy_name}:{pport}:{self._server_addr}', - '--proxy-cacert', self.env.ca.cert_file, - ] - if proto == 'h2': -@@ -408,24 +513,33 @@ class CurlClient: - else: - xargs = [ - '--proxy', f'http://{proxy_name}:{self.env.proxy_port}/', -- '--resolve', f'{proxy_name}:{self.env.proxy_port}:127.0.0.1', -+ '--resolve', f'{proxy_name}:{self.env.proxy_port}:{self._server_addr}', - ] - if tunnel: - xargs.append('--proxytunnel') - return xargs - - def http_get(self, url: str, extra_args: Optional[List[str]] = None, -- def_tracing: bool = True, with_profile: bool = False): -- return self._raw(url, options=extra_args, with_stats=False, -- def_tracing=def_tracing, with_profile=with_profile) -+ alpn_proto: Optional[str] = None, -+ def_tracing: bool = True, -+ with_stats: bool = False, -+ with_profile: bool = False, -+ with_tcpdump: bool = False): -+ return self._raw(url, options=extra_args, -+ with_stats=with_stats, -+ alpn_proto=alpn_proto, -+ def_tracing=def_tracing, -+ with_profile=with_profile, -+ with_tcpdump=with_tcpdump) - - def http_download(self, urls: List[str], - alpn_proto: Optional[str] = None, - with_stats: bool = True, - with_headers: bool = False, - with_profile: bool = False, -+ with_tcpdump: bool = False, - no_save: bool = False, -- extra_args: List[str] = None): -+ extra_args: Optional[List[str]] = None): - if extra_args is None: - extra_args = [] - if no_save: -@@ -446,13 +560,15 @@ class CurlClient: - return self._raw(urls, alpn_proto=alpn_proto, options=extra_args, - with_stats=with_stats, - with_headers=with_headers, -- with_profile=with_profile) -+ with_profile=with_profile, -+ with_tcpdump=with_tcpdump) - - def http_upload(self, urls: List[str], data: str, - alpn_proto: Optional[str] = None, - with_stats: bool = True, - with_headers: bool = False, - with_profile: bool = False, -+ with_tcpdump: bool = False, - extra_args: Optional[List[str]] = None): - if extra_args is None: - extra_args = [] -@@ -466,6 +582,26 @@ class CurlClient: - return self._raw(urls, alpn_proto=alpn_proto, options=extra_args, - with_stats=with_stats, - with_headers=with_headers, -+ with_profile=with_profile, -+ with_tcpdump=with_tcpdump) -+ -+ def http_delete(self, urls: List[str], -+ alpn_proto: Optional[str] = None, -+ with_stats: bool = True, -+ with_profile: bool = False, -+ extra_args: Optional[List[str]] = None): -+ if extra_args is None: -+ extra_args = [] -+ extra_args.extend([ -+ '-X', 'DELETE', '-o', '/dev/null', -+ ]) -+ if with_stats: -+ extra_args.extend([ -+ '-w', '%{json}\\n' -+ ]) -+ return self._raw(urls, alpn_proto=alpn_proto, options=extra_args, -+ with_stats=with_stats, -+ with_headers=False, - with_profile=with_profile) - - def http_put(self, urls: List[str], data=None, fdata=None, -@@ -513,6 +649,98 @@ class CurlClient: - with_stats=with_stats, - with_headers=with_headers) - -+ def ftp_get(self, urls: List[str], -+ with_stats: bool = True, -+ with_profile: bool = False, -+ with_tcpdump: bool = False, -+ no_save: bool = False, -+ extra_args: Optional[List[str]] = None): -+ if extra_args is None: -+ extra_args = [] -+ if no_save: -+ extra_args.extend([ -+ '-o', '/dev/null', -+ ]) -+ else: -+ extra_args.extend([ -+ '-o', 'download_#1.data', -+ ]) -+ # remove any existing ones -+ for i in range(100): -+ self._rmf(self.download_file(i)) -+ if with_stats: -+ extra_args.extend([ -+ '-w', '%{json}\\n' -+ ]) -+ return self._raw(urls, options=extra_args, -+ with_stats=with_stats, -+ with_headers=False, -+ with_profile=with_profile, -+ with_tcpdump=with_tcpdump) -+ -+ def ftp_ssl_get(self, urls: List[str], -+ with_stats: bool = True, -+ with_profile: bool = False, -+ with_tcpdump: bool = False, -+ no_save: bool = False, -+ extra_args: Optional[List[str]] = None): -+ if extra_args is None: -+ extra_args = [] -+ extra_args.extend([ -+ '--ssl-reqd', -+ ]) -+ return self.ftp_get(urls=urls, with_stats=with_stats, -+ with_profile=with_profile, no_save=no_save, -+ with_tcpdump=with_tcpdump, -+ extra_args=extra_args) -+ -+ def ftp_upload(self, urls: List[str], -+ fupload: Optional[Any] = None, -+ updata: Optional[str] = None, -+ with_stats: bool = True, -+ with_profile: bool = False, -+ with_tcpdump: bool = False, -+ extra_args: Optional[List[str]] = None): -+ if extra_args is None: -+ extra_args = [] -+ if fupload is not None: -+ extra_args.extend([ -+ '--upload-file', fupload -+ ]) -+ elif updata is not None: -+ extra_args.extend([ -+ '--upload-file', '-' -+ ]) -+ else: -+ raise Exception('need either file or data to upload') -+ if with_stats: -+ extra_args.extend([ -+ '-w', '%{json}\\n' -+ ]) -+ return self._raw(urls, options=extra_args, -+ intext=updata, -+ with_stats=with_stats, -+ with_headers=False, -+ with_profile=with_profile, -+ with_tcpdump=with_tcpdump) -+ -+ def ftp_ssl_upload(self, urls: List[str], -+ fupload: Optional[Any] = None, -+ updata: Optional[str] = None, -+ with_stats: bool = True, -+ with_profile: bool = False, -+ with_tcpdump: bool = False, -+ extra_args: Optional[List[str]] = None): -+ if extra_args is None: -+ extra_args = [] -+ extra_args.extend([ -+ '--ssl-reqd', -+ ]) -+ return self.ftp_upload(urls=urls, fupload=fupload, updata=updata, -+ with_stats=with_stats, with_profile=with_profile, -+ with_tcpdump=with_tcpdump, -+ extra_args=extra_args) -+ - def response_file(self, idx: int): - return os.path.join(self._run_dir, f'download_{idx}.data') - -@@ -528,57 +756,67 @@ class CurlClient: - my_args.extend(args) - return self._run(args=my_args, with_stats=with_stats, with_profile=with_profile) - -- def _run(self, args, intext='', with_stats: bool = False, with_profile: bool = True): -+ def _run(self, args, intext='', with_stats: bool = False, -+ with_profile: bool = True, with_tcpdump: bool = False): - self._rmf(self._stdoutfile) - self._rmf(self._stderrfile) - self._rmf(self._headerfile) -- started_at = datetime.now() - exception = None - profile = None -+ tcpdump = None -+ started_at = datetime.now() -+ if with_tcpdump: -+ tcpdump = RunTcpDump(self.env, self._run_dir) -+ tcpdump.start() - try: -- with open(self._stdoutfile, 'w') as cout: -- with open(self._stderrfile, 'w') as cerr: -- if with_profile: -- started_at = datetime.now() -- end_at = started_at + timedelta(seconds=self._timeout) \ -- if self._timeout else None -- log.info(f'starting: {args}') -- p = subprocess.Popen(args, stderr=cerr, stdout=cout, -- cwd=self._run_dir, shell=False) -- profile = RunProfile(p.pid, started_at, self._run_dir) -- if intext is not None and False: -- p.communicate(input=intext.encode(), timeout=1) -- ptimeout = 0.0 -- while True: -- try: -- p.wait(timeout=ptimeout) -- break -- except subprocess.TimeoutExpired: -- if end_at and datetime.now() >= end_at: -- p.kill() -- raise subprocess.TimeoutExpired(cmd=args, timeout=self._timeout) -- profile.sample() -- ptimeout = 0.01 -- exitcode = p.returncode -- profile.finish() -- log.info(f'done: exit={exitcode}, profile={profile}') -- else: -- p = subprocess.run(args, stderr=cerr, stdout=cout, -- cwd=self._run_dir, shell=False, -- input=intext.encode() if intext else None, -- timeout=self._timeout) -- exitcode = p.returncode -+ with open(self._stdoutfile, 'w') as cout, open(self._stderrfile, 'w') as cerr: -+ if with_profile: -+ end_at = started_at + timedelta(seconds=self._timeout) \ -+ if self._timeout else None -+ log.info(f'starting: {args}') -+ p = subprocess.Popen(args, stderr=cerr, stdout=cout, -+ cwd=self._run_dir, shell=False, -+ env=self._run_env) -+ profile = RunProfile(p.pid, started_at, self._run_dir) -+ if intext is not None and False: -+ p.communicate(input=intext.encode(), timeout=1) -+ ptimeout = 0.0 -+ while True: -+ try: -+ p.wait(timeout=ptimeout) -+ break -+ except subprocess.TimeoutExpired: -+ if end_at and datetime.now() >= end_at: -+ p.kill() -+ raise subprocess.TimeoutExpired(cmd=args, timeout=self._timeout) -+ profile.sample() -+ ptimeout = 0.01 -+ exitcode = p.returncode -+ profile.finish() -+ log.info(f'done: exit={exitcode}, profile={profile}') -+ else: -+ p = subprocess.run(args, stderr=cerr, stdout=cout, -+ cwd=self._run_dir, shell=False, -+ input=intext.encode() if intext else None, -+ timeout=self._timeout, -+ env=self._run_env) -+ exitcode = p.returncode - except subprocess.TimeoutExpired: -- log.warning(f'Timeout after {self._timeout}s: {args}') -+ now = datetime.now() -+ duration = now - started_at -+ log.warning(f'Timeout at {now} after {duration.total_seconds()}s ' -+ f'(configured {self._timeout}s): {args}') - exitcode = -1 - exception = 'TimeoutExpired' -+ if tcpdump: -+ tcpdump.finish() - coutput = open(self._stdoutfile).readlines() - cerrput = open(self._stderrfile).readlines() - return ExecResult(args=args, exit_code=exitcode, exception=exception, - stdout=coutput, stderr=cerrput, - duration=datetime.now() - started_at, - with_stats=with_stats, -- profile=profile) -+ profile=profile, tcpdump=tcpdump) - - def _raw(self, urls, intext='', timeout=None, options=None, insecure=False, - alpn_proto: Optional[str] = None, -@@ -586,17 +824,16 @@ class CurlClient: - with_stats=False, - with_headers=True, - def_tracing=True, -- with_profile=False): -+ with_profile=False, -+ with_tcpdump=False): - args = self._complete_args( - urls=urls, timeout=timeout, options=options, insecure=insecure, - alpn_proto=alpn_proto, force_resolve=force_resolve, - with_headers=with_headers, def_tracing=def_tracing) - r = self._run(args, intext=intext, with_stats=with_stats, -- with_profile=with_profile) -+ with_profile=with_profile, with_tcpdump=with_tcpdump) - if r.exit_code == 0 and with_headers: - self._parse_headerfile(self._headerfile, r=r) -- if r.json: -- r.response["json"] = r.json - return r - - def _complete_args(self, urls, timeout=None, options=None, -@@ -608,13 +845,15 @@ class CurlClient: - urls = [urls] - - args = [self._curl, "-s", "--path-as-is"] -+ if 'CURL_TEST_EVENT' in os.environ: -+ args.append('--test-event') -+ - if with_headers: - args.extend(["-D", self._headerfile]) - if def_tracing is not False and not self._silent: - args.extend(['-v', '--trace-ids', '--trace-time']) - if self.env.verbose > 1: - args.extend(['--trace-config', 'http/2,http/3,h2-proxy,h1-proxy']) -- pass - - active_options = options - if options is not None and '--next' in options: -@@ -641,13 +880,15 @@ class CurlClient: - if force_resolve and u.hostname and u.hostname != 'localhost' \ - and not re.match(r'^(\d+|\[|:).*', u.hostname): - port = u.port if u.port else 443 -- args.extend(["--resolve", f"{u.hostname}:{port}:127.0.0.1"]) -+ args.extend([ -+ '--resolve', f'{u.hostname}:{port}:{self._server_addr}', -+ ]) - if timeout is not None and int(timeout) > 0: - args.extend(["--connect-timeout", str(int(timeout))]) - args.append(url) - return args - -- def _parse_headerfile(self, headerfile: str, r: ExecResult = None) -> ExecResult: -+ def _parse_headerfile(self, headerfile: str, r: Optional[ExecResult] = None) -> ExecResult: - lines = open(headerfile).readlines() - if r is None: - r = ExecResult(args=[], exit_code=0, stdout=[], stderr=[]) -diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py -index a207059dc..4eb0eb765 100644 ---- a/tests/http/testenv/env.py -+++ b/tests/http/testenv/env.py -@@ -27,16 +27,14 @@ - import logging - import os - import re -+import shutil - import socket - import subprocess --import sys -+import tempfile - from configparser import ConfigParser, ExtendedInterpolation --from datetime import timedelta - from typing import Optional - --import pytest -- --from .certs import CertificateSpec, TestCA, Credentials -+from .certs import CertificateSpec, Credentials, TestCA - from .ports import alloc_ports - - -@@ -52,10 +50,9 @@ def init_config_from(conf_path): - - - TESTS_HTTPD_PATH = os.path.dirname(os.path.dirname(__file__)) --DEF_CONFIG = init_config_from(os.path.join(TESTS_HTTPD_PATH, 'config.ini')) -- --TOP_PATH = os.path.dirname(os.path.dirname(TESTS_HTTPD_PATH)) --CURL = os.path.join(TOP_PATH, 'src/curl') -+TOP_PATH = os.path.join(os.getcwd(), os.path.pardir) -+DEF_CONFIG = init_config_from(os.path.join(TOP_PATH, 'tests', 'http', 'config.ini')) -+CURL = os.path.join(TOP_PATH, 'src', 'curl') - - - class EnvConfig: -@@ -64,50 +61,63 @@ class EnvConfig: - self.tests_dir = TESTS_HTTPD_PATH - self.gen_dir = os.path.join(self.tests_dir, 'gen') - self.project_dir = os.path.dirname(os.path.dirname(self.tests_dir)) -+ self.build_dir = TOP_PATH - self.config = DEF_CONFIG - # check cur and its features - self.curl = CURL - if 'CURL' in os.environ: - self.curl = os.environ['CURL'] - self.curl_props = { -- 'version': None, -- 'os': None, -- 'fullname': None, -- 'features': [], -- 'protocols': [], -- 'libs': [], -- 'lib_versions': [], -+ 'version_string': '', -+ 'version': '', -+ 'os': '', -+ 'fullname': '', -+ 'features_string': '', -+ 'features': set(), -+ 'protocols_string': '', -+ 'protocols': set(), -+ 'libs': set(), -+ 'lib_versions': set(), - } -+ self.curl_is_debug = False - self.curl_protos = [] - p = subprocess.run(args=[self.curl, '-V'], - capture_output=True, text=True) - if p.returncode != 0: -- assert False, f'{self.curl} -V failed with exit code: {p.returncode}' -- for l in p.stdout.splitlines(keepends=False): -- if l.startswith('curl '): -- m = re.match(r'^curl (?P\S+) (?P\S+) (?P.*)$', l) -+ raise RuntimeError(f'{self.curl} -V failed with exit code: {p.returncode}') -+ if p.stderr.startswith('WARNING:'): -+ self.curl_is_debug = True -+ for line in p.stdout.splitlines(keepends=False): -+ if line.startswith('curl '): -+ self.curl_props['version_string'] = line -+ m = re.match(r'^curl (?P\S+) (?P\S+) (?P.*)$', line) - if m: - self.curl_props['fullname'] = m.group(0) - self.curl_props['version'] = m.group('version') - self.curl_props['os'] = m.group('os') -- self.curl_props['lib_versions'] = [ -+ self.curl_props['lib_versions'] = { - lib.lower() for lib in m.group('libs').split(' ') -- ] -- self.curl_props['libs'] = [ -- re.sub(r'/.*', '', lib) for lib in self.curl_props['lib_versions'] -- ] -- if l.startswith('Features: '): -- self.curl_props['features'] = [ -- feat.lower() for feat in l[10:].split(' ') -- ] -- if l.startswith('Protocols: '): -- self.curl_props['protocols'] = [ -- prot.lower() for prot in l[11:].split(' ') -- ] -+ } -+ self.curl_props['libs'] = { -+ re.sub(r'/[a-z0-9.-]*', '', lib) for lib in self.curl_props['lib_versions'] -+ } -+ if line.startswith('Features: '): -+ self.curl_props['features_string'] = line[10:] -+ self.curl_props['features'] = { -+ feat.lower() for feat in line[10:].split(' ') -+ } -+ if line.startswith('Protocols: '): -+ self.curl_props['protocols_string'] = line[11:] -+ self.curl_props['protocols'] = { -+ prot.lower() for prot in line[11:].split(' ') -+ } - - self.ports = alloc_ports(port_specs={ -+ 'ftp': socket.SOCK_STREAM, -+ 'ftps': socket.SOCK_STREAM, - 'http': socket.SOCK_STREAM, - 'https': socket.SOCK_STREAM, -+ 'nghttpx_https': socket.SOCK_STREAM, - 'proxy': socket.SOCK_STREAM, - 'proxys': socket.SOCK_STREAM, - 'h2proxys': socket.SOCK_STREAM, -@@ -129,11 +139,14 @@ class EnvConfig: - self.htdocs_dir = os.path.join(self.gen_dir, 'htdocs') - self.tld = 'http.curl.se' - self.domain1 = f"one.{self.tld}" -+ self.domain1brotli = f"brotli.one.{self.tld}" - self.domain2 = f"two.{self.tld}" -+ self.ftp_domain = f"ftp.{self.tld}" - self.proxy_domain = f"proxy.{self.tld}" - self.cert_specs = [ -- CertificateSpec(domains=[self.domain1, 'localhost'], key_type='rsa2048'), -+ CertificateSpec(domains=[self.domain1, self.domain1brotli, 'localhost', '127.0.0.1'], key_type='rsa2048'), - CertificateSpec(domains=[self.domain2], key_type='rsa2048'), -+ CertificateSpec(domains=[self.ftp_domain], key_type='rsa2048'), - CertificateSpec(domains=[self.proxy_domain, '127.0.0.1'], key_type='rsa2048'), - CertificateSpec(name="clientsX", sub_specs=[ - CertificateSpec(name="user1", client=True), -@@ -167,10 +180,47 @@ class EnvConfig: - if p.returncode != 0: - # not a working caddy - self.caddy = None -- self._caddy_version = re.sub(r' .*', '', p.stdout.strip()) -- except: -+ m = re.match(r'v?(\d+\.\d+\.\d+).*', p.stdout) -+ if m: -+ self._caddy_version = m.group(1) -+ else: -+ raise RuntimeError(f'Unable to determine cadd version from: {p.stdout}') -+ # TODO: specify specific exceptions here -+ except: # noqa: E722 - self.caddy = None - -+ self.vsftpd = self.config['vsftpd']['vsftpd'] -+ self._vsftpd_version = None -+ if self.vsftpd is not None: -+ try: -+ with tempfile.TemporaryFile('w+') as tmp: -+ p = subprocess.run(args=[self.vsftpd, '-v'], -+ capture_output=True, text=True, stdin=tmp) -+ if p.returncode != 0: -+ # not a working vsftpd -+ self.vsftpd = None -+ if p.stderr: -+ ver_text = p.stderr -+ else: -+ # Oddly, some versions of vsftpd write to stdin (!) -+ # instead of stderr, which is odd but works. If there -+ # is nothing on stderr, read the file on stdin and use -+ # any data there instead. -+ tmp.seek(0) -+ ver_text = tmp.read() -+ m = re.match(r'vsftpd: version (\d+\.\d+\.\d+)', ver_text) -+ if m: -+ self._vsftpd_version = m.group(1) -+ elif len(p.stderr) == 0: -+ # vsftp does not use stdout or stderr for printing its version... -.- -+ self._vsftpd_version = 'unknown' -+ else: -+ raise Exception(f'Unable to determine VsFTPD version from: {p.stderr}') -+ except Exception: -+ self.vsftpd = None -+ -+ self._tcpdump = shutil.which('tcpdump') -+ - @property - def httpd_version(self): - if self._httpd_version is None and self.apxs is not None: -@@ -181,8 +231,8 @@ class EnvConfig: - log.error(f'{self.apxs} failed to query HTTPD_VERSION: {p}') - else: - self._httpd_version = p.stdout.strip() -- except Exception as e: -- log.error(f'{self.apxs} failed to run: {e}') -+ except Exception: -+ log.exception(f'{self.apxs} failed to run') - return self._httpd_version - - def versiontuple(self, v): -@@ -195,6 +245,12 @@ class EnvConfig: - hv = self.versiontuple(self.httpd_version) - return hv >= self.versiontuple(minv) - -+ def caddy_is_at_least(self, minv): -+ if self.caddy_version is None: -+ return False -+ hv = self.versiontuple(self.caddy_version) -+ return hv >= self.versiontuple(minv) -+ - def is_complete(self) -> bool: - return os.path.isfile(self.httpd) and \ - os.path.isfile(self.apachectl) and \ -@@ -203,13 +259,13 @@ class EnvConfig: - - def get_incomplete_reason(self) -> Optional[str]: - if self.httpd is None or len(self.httpd.strip()) == 0: -- return f'httpd not configured, see `--with-test-httpd=`' -+ return 'httpd not configured, see `--with-test-httpd=`' - if not os.path.isfile(self.httpd): - return f'httpd ({self.httpd}) not found' - if not os.path.isfile(self.apachectl): - return f'apachectl ({self.apachectl}) not found' - if self.apxs is None: -- return f"command apxs not found (commonly provided in apache2-dev)" -+ return "command apxs not found (commonly provided in apache2-dev)" - if not os.path.isfile(self.apxs): - return f"apxs ({self.apxs}) not found" - return None -@@ -222,6 +278,14 @@ class EnvConfig: - def caddy_version(self): - return self._caddy_version - -+ @property -+ def vsftpd_version(self): -+ return self._vsftpd_version -+ -+ @property -+ def tcpdmp(self) -> Optional[str]: -+ return self._tcpdump -+ - - class Env: - -@@ -245,7 +309,7 @@ class Env: - - @staticmethod - def have_ssl_curl() -> bool: -- return 'ssl' in Env.CONFIG.curl_props['features'] -+ return Env.curl_has_feature('ssl') or Env.curl_has_feature('multissl') - - @staticmethod - def have_h2_curl() -> bool: -@@ -259,10 +323,28 @@ class Env: - def curl_uses_lib(libname: str) -> bool: - return libname.lower() in Env.CONFIG.curl_props['libs'] - -+ @staticmethod -+ def curl_uses_ossl_quic() -> bool: -+ if Env.have_h3_curl(): -+ return not Env.curl_uses_lib('ngtcp2') and Env.curl_uses_lib('nghttp3') -+ return False -+ -+ @staticmethod -+ def curl_version_string() -> str: -+ return Env.CONFIG.curl_props['version_string'] -+ -+ @staticmethod -+ def curl_features_string() -> str: -+ return Env.CONFIG.curl_props['features_string'] -+ - @staticmethod - def curl_has_feature(feature: str) -> bool: - return feature.lower() in Env.CONFIG.curl_props['features'] - -+ @staticmethod -+ def curl_protocols_string() -> str: -+ return Env.CONFIG.curl_props['protocols_string'] -+ - @staticmethod - def curl_has_protocol(protocol: str) -> bool: - return protocol.lower() in Env.CONFIG.curl_props['protocols'] -@@ -276,7 +358,7 @@ class Env: - return 'unknown' - - @staticmethod -- def curl_lib_version_at_least(libname: str, min_version) -> str: -+ def curl_lib_version_at_least(libname: str, min_version) -> bool: - lversion = Env.curl_lib_version(libname) - if lversion != 'unknown': - return Env.CONFIG.versiontuple(min_version) <= \ -@@ -295,6 +377,10 @@ class Env: - def curl_version() -> str: - return Env.CONFIG.curl_props['version'] - -+ @staticmethod -+ def curl_is_debug() -> bool: -+ return Env.CONFIG.curl_is_debug -+ - @staticmethod - def have_h3() -> bool: - return Env.have_h3_curl() and Env.have_h3_server() -@@ -311,6 +397,10 @@ class Env: - def caddy_version() -> str: - return Env.CONFIG.caddy_version - -+ @staticmethod -+ def caddy_is_at_least(minv) -> bool: -+ return Env.CONFIG.caddy_is_at_least(minv) -+ - @staticmethod - def httpd_is_at_least(minv) -> bool: - return Env.CONFIG.httpd_is_at_least(minv) -@@ -319,6 +409,18 @@ class Env: - def has_caddy() -> bool: - return Env.CONFIG.caddy is not None - -+ @staticmethod -+ def has_vsftpd() -> bool: -+ return Env.CONFIG.vsftpd is not None -+ -+ @staticmethod -+ def vsftpd_version() -> str: -+ return Env.CONFIG.vsftpd_version -+ -+ @staticmethod -+ def tcpdump() -> Optional[str]: -+ return Env.CONFIG.tcpdmp -+ - def __init__(self, pytestconfig=None): - self._verbose = pytestconfig.option.verbose \ - if pytestconfig is not None else 0 -@@ -364,6 +466,10 @@ class Env: - def project_dir(self) -> str: - return self.CONFIG.project_dir - -+ @property -+ def build_dir(self) -> str: -+ return self.CONFIG.build_dir -+ - @property - def ca(self): - return self._ca -@@ -372,14 +478,26 @@ class Env: - def htdocs_dir(self) -> str: - return self.CONFIG.htdocs_dir - -+ @property -+ def tld(self) -> str: -+ return self.CONFIG.tld -+ - @property - def domain1(self) -> str: - return self.CONFIG.domain1 - -+ @property -+ def domain1brotli(self) -> str: -+ return self.CONFIG.domain1brotli -+ - @property - def domain2(self) -> str: - return self.CONFIG.domain2 - -+ @property -+ def ftp_domain(self) -> str: -+ return self.CONFIG.ftp_domain -+ - @property - def proxy_domain(self) -> str: - return self.CONFIG.proxy_domain -@@ -392,6 +510,10 @@ class Env: - def https_port(self) -> int: - return self.CONFIG.ports['https'] - -+ @property -+ def nghttpx_https_port(self) -> int: -+ return self.CONFIG.ports['nghttpx_https'] -+ - @property - def h3_port(self) -> int: - return self.https_port -@@ -404,6 +526,14 @@ class Env: - def proxys_port(self) -> int: - return self.CONFIG.ports['proxys'] - -+ @property -+ def ftp_port(self) -> int: -+ return self.CONFIG.ports['ftp'] -+ -+ @property -+ def ftps_port(self) -> int: -+ return self.CONFIG.ports['ftps'] -+ - @property - def h2proxys_port(self) -> int: - return self.CONFIG.ports['h2proxys'] -@@ -424,6 +554,10 @@ class Env: - def caddy_http_port(self) -> int: - return self.CONFIG.ports['caddy'] - -+ @property -+ def vsftpd(self) -> str: -+ return self.CONFIG.vsftpd -+ - @property - def ws_port(self) -> int: - return self.CONFIG.ports['ws'] -@@ -457,33 +591,30 @@ class Env: - def ci_run(self) -> bool: - return "CURL_CI" in os.environ - -- def authority_for(self, domain: str, alpn_proto: Optional[str] = None): -+ def port_for(self, alpn_proto: Optional[str] = None): - if alpn_proto is None or \ - alpn_proto in ['h2', 'http/1.1', 'http/1.0', 'http/0.9']: -- return f'{domain}:{self.https_port}' -+ return self.https_port - if alpn_proto in ['h3']: -- return f'{domain}:{self.h3_port}' -- return f'{domain}:{self.http_port}' -+ return self.h3_port -+ return self.http_port -+ -+ def authority_for(self, domain: str, alpn_proto: Optional[str] = None): -+ return f'{domain}:{self.port_for(alpn_proto=alpn_proto)}' - -- def make_data_file(self, indir: str, fname: str, fsize: int) -> str: -+ def make_data_file(self, indir: str, fname: str, fsize: int, -+ line_length: int = 1024) -> str: -+ if line_length < 11: -+ raise RuntimeError('line_length less than 11 not supported') - fpath = os.path.join(indir, fname) - s10 = "0123456789" -- s = (101 * s10) + s10[0:3] -+ s = round((line_length / 10) + 1) * s10 -+ s = s[0:line_length-11] - with open(fpath, 'w') as fd: -- for i in range(int(fsize / 1024)): -+ for i in range(int(fsize / line_length)): - fd.write(f"{i:09d}-{s}\n") -- remain = int(fsize % 1024) -+ remain = int(fsize % line_length) - if remain != 0: -- i = int(fsize / 1024) + 1 -- s = f"{i:09d}-{s}\n" -- fd.write(s[0:remain]) -+ i = int(fsize / line_length) + 1 -+ fd.write(f"{i:09d}-{s}"[0:remain-1] + "\n") - return fpath -- -- def make_clients(self): -- client_dir = os.path.join(self.project_dir, 'tests/http/clients') -- p = subprocess.run(['make'], capture_output=True, text=True, -- cwd=client_dir) -- if p.returncode != 0: -- pytest.exit(f"`make`in {client_dir} failed:\n{p.stderr}") -- return False -- return True -diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py -index c04c22699..f3ca46f13 100644 ---- a/tests/http/testenv/httpd.py -+++ b/tests/http/testenv/httpd.py -@@ -32,6 +32,7 @@ from datetime import timedelta, datetime - from json import JSONEncoder - import time - from typing import List, Union, Optional -+import copy - - from .curl import CurlClient, ExecResult - from .env import Env -@@ -50,6 +51,7 @@ class Httpd: - 'alias', 'env', 'filter', 'headers', 'mime', 'setenvif', - 'socache_shmcb', - 'rewrite', 'http2', 'ssl', 'proxy', 'proxy_http', 'proxy_connect', -+ 'brotli', - 'mpm_event', - ] - COMMON_MODULES_DIRS = [ -@@ -77,6 +79,7 @@ class Httpd: - self._auth_digest = True - self._proxy_auth_basic = proxy_auth - self._extra_configs = {} -+ self._loaded_extra_configs = None - assert env.apxs - p = subprocess.run(args=[env.apxs, '-q', 'libexecdir'], - capture_output=True, text=True) -@@ -84,7 +87,7 @@ class Httpd: - raise Exception(f'{env.apxs} failed to query libexecdir: {p}') - self._mods_dir = p.stdout.strip() - if self._mods_dir is None: -- raise Exception(f'apache modules dir cannot be found') -+ raise Exception('apache modules dir cannot be found') - if not os.path.exists(self._mods_dir): - raise Exception(f'apache modules dir does not exist: {self._mods_dir}') - self._process = None -@@ -114,9 +117,7 @@ class Httpd: - self._proxy_auth_basic = active - - def _run(self, args, intext=''): -- env = {} -- for key, val in os.environ.items(): -- env[key] = val -+ env = os.environ.copy() - env['APACHE_RUN_DIR'] = self._run_dir - env['APACHE_RUN_USER'] = os.environ['USER'] - env['APACHE_LOCK_DIR'] = self._lock_dir -@@ -150,10 +151,12 @@ class Httpd: - if r.exit_code != 0: - log.error(f'failed to start httpd: {r}') - return False -+ self._loaded_extra_configs = copy.deepcopy(self._extra_configs) - return self.wait_live(timeout=timedelta(seconds=5)) - - def stop(self): - r = self._apachectl('stop') -+ self._loaded_extra_configs = None - if r.exit_code == 0: - return self.wait_dead(timeout=timedelta(seconds=5)) - log.fatal(f'stopping httpd failed: {r}') -@@ -166,10 +169,17 @@ class Httpd: - def reload(self): - self._write_config() - r = self._apachectl("graceful") -+ self._loaded_extra_configs = None - if r.exit_code != 0: - log.error(f'failed to reload httpd: {r}') -+ self._loaded_extra_configs = copy.deepcopy(self._extra_configs) - return self.wait_live(timeout=timedelta(seconds=5)) - -+ def reload_if_config_changed(self): -+ if self._loaded_extra_configs == self._extra_configs: -+ return True -+ return self.reload() -+ - def wait_dead(self, timeout: timedelta): - curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout -@@ -203,11 +213,15 @@ class Httpd: - - def _write_config(self): - domain1 = self.env.domain1 -+ domain1brotli = self.env.domain1brotli - creds1 = self.env.get_credentials(domain1) -+ assert creds1 # convince pytype this isn't None - domain2 = self.env.domain2 - creds2 = self.env.get_credentials(domain2) -+ assert creds2 # convince pytype this isn't None - proxy_domain = self.env.proxy_domain - proxy_creds = self.env.get_credentials(proxy_domain) -+ assert proxy_creds # convince pytype this isn't None - self._mkpath(self._conf_dir) - self._mkpath(self._logs_dir) - self._mkpath(self._tmp_dir) -@@ -236,44 +250,45 @@ class Httpd: - if os.path.exists(os.path.join(self._mods_dir, f'mod_{m}.so')): - fd.write(f'LoadModule {m}_module "{self._mods_dir}/mod_{m}.so"\n') - if Httpd.MOD_CURLTEST is not None: -- fd.write(f'LoadModule curltest_module \"{Httpd.MOD_CURLTEST}\"\n') -+ fd.write(f'LoadModule curltest_module "{Httpd.MOD_CURLTEST}"\n') - conf = [ # base server config - f'ServerRoot "{self._apache_dir}"', -- f'DefaultRuntimeDir logs', -- f'PidFile httpd.pid', -+ 'DefaultRuntimeDir logs', -+ 'PidFile httpd.pid', - f'ErrorLog {self._error_log}', - f'LogLevel {self._get_log_level()}', -- f'StartServers 4', -- f'H2MinWorkers 16', -- f'H2MaxWorkers 256', -- f'H2Direct on', -+ 'StartServers 4', -+ 'ReadBufferSize 16000', -+ 'H2MinWorkers 16', -+ 'H2MaxWorkers 256', - f'Listen {self.env.http_port}', - f'Listen {self.env.https_port}', - f'Listen {self.env.proxy_port}', - f'Listen {self.env.proxys_port}', - f'TypesConfig "{self._conf_dir}/mime.types', -- f'SSLSessionCache "shmcb:ssl_gcache_data(32000)"', -+ 'SSLSessionCache "shmcb:ssl_gcache_data(32000)"', - ] - if 'base' in self._extra_configs: - conf.extend(self._extra_configs['base']) - conf.extend([ # plain http host for domain1 - f'', - f' ServerName {domain1}', -- f' ServerAlias localhost', -+ ' ServerAlias localhost', - f' DocumentRoot "{self._docs_dir}"', -- f' Protocols h2c http/1.1', -+ ' Protocols h2c http/1.1', -+ ' H2Direct on', - ]) - conf.extend(self._curltest_conf(domain1)) - conf.extend([ -- f'', -- f'', -+ '', -+ '', - ]) - conf.extend([ # https host for domain1, h1 + h2 - f'', - f' ServerName {domain1}', -- f' ServerAlias localhost', -- f' Protocols h2 http/1.1', -- f' SSLEngine on', -+ ' ServerAlias localhost', -+ ' Protocols h2 http/1.1', -+ ' SSLEngine on', - f' SSLCertificateFile {creds1.cert_file}', - f' SSLCertificateKeyFile {creds1.pkey_file}', - f' DocumentRoot "{self._docs_dir}"', -@@ -282,14 +297,44 @@ class Httpd: - if domain1 in self._extra_configs: - conf.extend(self._extra_configs[domain1]) - conf.extend([ -- f'', -- f'', -+ '', -+ '', -+ ]) -+ # Alternate to domain1 with BROTLI compression -+ conf.extend([ # https host for domain1, h1 + h2 -+ f'', -+ f' ServerName {domain1brotli}', -+ ' Protocols h2 http/1.1', -+ ' SSLEngine on', -+ f' SSLCertificateFile {creds1.cert_file}', -+ f' SSLCertificateKeyFile {creds1.pkey_file}', -+ f' DocumentRoot "{self._docs_dir}"', -+ ' SetOutputFilter BROTLI_COMPRESS', -+ ]) -+ conf.extend(self._curltest_conf(domain1)) -+ if domain1 in self._extra_configs: -+ conf.extend(self._extra_configs[domain1]) -+ conf.extend([ -+ '', -+ '', -+ ]) -+ conf.extend([ # plain http host for domain2 -+ f'', -+ f' ServerName {domain2}', -+ ' ServerAlias localhost', -+ f' DocumentRoot "{self._docs_dir}"', -+ ' Protocols h2c http/1.1', -+ ]) -+ conf.extend(self._curltest_conf(domain2)) -+ conf.extend([ -+ '', -+ '', - ]) - conf.extend([ # https host for domain2, no h2 - f'', - f' ServerName {domain2}', -- f' Protocols http/1.1', -- f' SSLEngine on', -+ ' Protocols http/1.1', -+ ' SSLEngine on', - f' SSLCertificateFile {creds2.cert_file}', - f' SSLCertificateKeyFile {creds2.pkey_file}', - f' DocumentRoot "{self._docs_dir}/two"', -@@ -298,39 +343,39 @@ class Httpd: - if domain2 in self._extra_configs: - conf.extend(self._extra_configs[domain2]) - conf.extend([ -- f'', -- f'', -+ '', -+ '', - ]) - conf.extend([ # http forward proxy - f'', - f' ServerName {proxy_domain}', -- f' Protocols h2c http/1.1', -- f' ProxyRequests On', -- f' H2ProxyRequests On', -- f' ProxyVia On', -+ ' Protocols h2c http/1.1', -+ ' ProxyRequests On', -+ ' H2ProxyRequests On', -+ ' ProxyVia On', - f' AllowCONNECT {self.env.http_port} {self.env.https_port}', - ]) - conf.extend(self._get_proxy_conf()) - conf.extend([ -- f'', -- f'', -+ '', -+ '', - ]) - conf.extend([ # https forward proxy - f'', - f' ServerName {proxy_domain}', -- f' Protocols h2 http/1.1', -- f' SSLEngine on', -+ ' Protocols h2 http/1.1', -+ ' SSLEngine on', - f' SSLCertificateFile {proxy_creds.cert_file}', - f' SSLCertificateKeyFile {proxy_creds.pkey_file}', -- f' ProxyRequests On', -- f' H2ProxyRequests On', -- f' ProxyVia On', -+ ' ProxyRequests On', -+ ' H2ProxyRequests On', -+ ' ProxyVia On', - f' AllowCONNECT {self.env.http_port} {self.env.https_port}', - ]) - conf.extend(self._get_proxy_conf()) - conf.extend([ -- f'', -- f'', -+ '', -+ '', - ]) - - fd.write("\n".join(conf)) -@@ -344,19 +389,19 @@ class Httpd: - def _get_proxy_conf(self): - if self._proxy_auth_basic: - return [ -- f' ', -- f' AuthType Basic', -- f' AuthName "Restricted Proxy"', -- f' AuthBasicProvider file', -+ ' ', -+ ' AuthType Basic', -+ ' AuthName "Restricted Proxy"', -+ ' AuthBasicProvider file', - f' AuthUserFile "{self._basic_passwords}"', -- f' Require user proxy', -- f' ', -+ ' Require user proxy', -+ ' ', - ] - else: - return [ -- f' ', -- f' Require ip 127.0.0.1', -- f' ', -+ ' ', -+ ' Require ip 127.0.0.1', -+ ' ', - ] - - def _get_log_level(self): -@@ -372,39 +417,44 @@ class Httpd: - lines = [] - if Httpd.MOD_CURLTEST is not None: - lines.extend([ -- f' Redirect 301 /curltest/echo301 /curltest/echo', -- f' Redirect 302 /curltest/echo302 /curltest/echo', -- f' Redirect 303 /curltest/echo303 /curltest/echo', -- f' Redirect 307 /curltest/echo307 /curltest/echo', -- f' ', -- f' SetHandler curltest-echo', -- f' ', -- f' ', -- f' SetHandler curltest-put', -- f' ', -- f' ', -- f' SetHandler curltest-tweak', -- f' ', -- f' Redirect 302 /tweak /curltest/tweak', -- f' ', -- f' SetHandler curltest-1_1-required', -- f' ', -- f' ', -- f' SetHandler curltest-tweak', -- f' SetEnv force-response-1.0 1', -- f' ', -- f' SetEnvIf Request_URI "/shutdown_unclean" ssl-unclean=1', -+ ' Redirect 302 /data.json.302 /data.json', -+ ' Redirect 301 /curltest/echo301 /curltest/echo', -+ ' Redirect 302 /curltest/echo302 /curltest/echo', -+ ' Redirect 303 /curltest/echo303 /curltest/echo', -+ ' Redirect 307 /curltest/echo307 /curltest/echo', -+ ' ', -+ ' SSLOptions StdEnvVars', -+ ' SetHandler curltest-sslinfo', -+ ' ', -+ ' ', -+ ' SetHandler curltest-echo', -+ ' ', -+ ' ', -+ ' SetHandler curltest-put', -+ ' ', -+ ' ', -+ ' SetHandler curltest-tweak', -+ ' ', -+ ' Redirect 302 /tweak /curltest/tweak', -+ ' ', -+ ' SetHandler curltest-1_1-required', -+ ' ', -+ ' ', -+ ' SetHandler curltest-tweak', -+ ' SetEnv force-response-1.0 1', -+ ' ', -+ ' SetEnvIf Request_URI "/shutdown_unclean" ssl-unclean=1', - ]) - if self._auth_digest: - lines.extend([ - f' ', -- f' AuthType Digest', -- f' AuthName "restricted area"', -+ ' AuthType Digest', -+ ' AuthName "restricted area"', - f' AuthDigestDomain "https://{servername}"', -- f' AuthBasicProvider file', -+ ' AuthBasicProvider file', - f' AuthUserFile "{self._digest_passwords}"', -- f' Require valid-user', -- f' ', -+ ' Require valid-user', -+ ' ', - - ]) - return lines -diff --git a/tests/http/testenv/mod_curltest/mod_curltest.c b/tests/http/testenv/mod_curltest/mod_curltest.c -index 4736fefdb..2b57a082b 100644 ---- a/tests/http/testenv/mod_curltest/mod_curltest.c -+++ b/tests/http/testenv/mod_curltest/mod_curltest.c -@@ -21,6 +21,8 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ -+#include -+ - #include - #include - #include -@@ -38,8 +40,10 @@ static int curltest_echo_handler(request_rec *r); - static int curltest_put_handler(request_rec *r); - static int curltest_tweak_handler(request_rec *r); - static int curltest_1_1_required(request_rec *r); -+static int curltest_sslinfo_handler(request_rec *r); - --AP_DECLARE_MODULE(curltest) = { -+AP_DECLARE_MODULE(curltest) = -+{ - STANDARD20_MODULE_STUFF, - NULL, /* func to create per dir config */ - NULL, /* func to merge per dir config */ -@@ -86,13 +90,14 @@ static void curltest_hooks(apr_pool_t *pool) - ap_hook_handler(curltest_put_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_handler(curltest_tweak_handler, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_handler(curltest_1_1_required, NULL, NULL, APR_HOOK_MIDDLE); -+ ap_hook_handler(curltest_sslinfo_handler, NULL, NULL, APR_HOOK_MIDDLE); - } - - #define SECS_PER_HOUR (60*60) - #define SECS_PER_DAY (24*SECS_PER_HOUR) - --static apr_status_t duration_parse(apr_interval_time_t *ptimeout, const char *value, -- const char *def_unit) -+static apr_status_t duration_parse(apr_interval_time_t *ptimeout, -+ const char *value, const char *def_unit) - { - char *endp; - apr_int64_t n; -@@ -102,7 +107,8 @@ static apr_status_t duration_parse(apr_interval_time_t *ptimeout, const char *va - return errno; - } - if(!endp || !*endp) { -- if (!def_unit) def_unit = "s"; -+ if(!def_unit) -+ def_unit = "s"; - } - else if(endp == value) { - return APR_EINVAL; -@@ -181,6 +187,8 @@ static int curltest_echo_handler(request_rec *r) - apr_status_t rv; - char buffer[8192]; - const char *ct; -+ apr_off_t die_after_len = -1, total_read_len = 0; -+ int just_die = 0, die_after_100 = 0; - long l; - - if(strcmp(r->handler, "curltest-echo")) { -@@ -191,29 +199,94 @@ static int curltest_echo_handler(request_rec *r) - } - - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "echo_handler: processing"); -+ if(r->args) { -+ apr_array_header_t *args = NULL; -+ int i; -+ args = apr_cstr_split(r->args, "&", 1, r->pool); -+ for(i = 0; i < args->nelts; ++i) { -+ char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *); -+ s = strchr(arg, '='); -+ if(s) { -+ *s = '\0'; -+ val = s + 1; -+ if(!strcmp("die_after", arg)) { -+ die_after_len = (apr_off_t)apr_atoi64(val); -+ continue; -+ } -+ else if(!strcmp("just_die", arg)) { -+ just_die = 1; -+ continue; -+ } -+ else if(!strcmp("die_after_100", arg)) { -+ die_after_100 = 1; -+ continue; -+ } -+ } -+ } -+ } -+ -+ if(just_die) { -+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, -+ "echo_handler: dying right away"); -+ /* Generate no HTTP response at all. */ -+ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); -+ r->connection->keepalive = AP_CONN_CLOSE; -+ return AP_FILTER_ERROR; -+ } -+ - r->status = 200; -- r->clength = -1; -- r->chunked = 1; -- apr_table_unset(r->headers_out, "Content-Length"); -+ if(die_after_len >= 0) { -+ r->clength = die_after_len + 1; -+ r->chunked = 0; -+ apr_table_set(r->headers_out, "Content-Length", -+ apr_ltoa(r->pool, (long)r->clength)); -+ } -+ else { -+ r->clength = -1; -+ r->chunked = 1; -+ apr_table_unset(r->headers_out, "Content-Length"); -+ } - /* Discourage content-encodings */ - apr_table_unset(r->headers_out, "Content-Encoding"); - apr_table_setn(r->subprocess_env, "no-brotli", "1"); - apr_table_setn(r->subprocess_env, "no-gzip", "1"); - - ct = apr_table_get(r->headers_in, "content-type"); -- ap_set_content_type(r, ct? ct : "application/octet-stream"); -+ ap_set_content_type(r, ct ? ct : "application/octet-stream"); - - bb = apr_brigade_create(r->pool, c->bucket_alloc); - /* copy any request body into the response */ -- if((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) goto cleanup; -+ rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); -+ if(rv) -+ goto cleanup; -+ if(die_after_100) { -+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, -+ "echo_handler: dying after 100-continue"); -+ /* Generate no HTTP response at all. */ -+ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); -+ r->connection->keepalive = AP_CONN_CLOSE; -+ return AP_FILTER_ERROR; -+ } - if(ap_should_client_block(r)) { - while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) { -+ total_read_len += l; -+ if(die_after_len >= 0 && total_read_len >= die_after_len) { -+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, -+ "echo_handler: dying after %ld bytes as requested", -+ (long)total_read_len); -+ ap_pass_brigade(r->output_filters, bb); -+ ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER"); -+ r->connection->keepalive = AP_CONN_CLOSE; -+ return DONE; -+ } - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "echo_handler: copying %ld bytes from request body", l); - rv = apr_brigade_write(bb, NULL, NULL, buffer, l); -- if (APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - rv = ap_pass_brigade(r->output_filters, bb); -- if (APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "echo_handler: passed %ld bytes from request body", l); - } -@@ -257,22 +330,27 @@ static int curltest_tweak_handler(request_rec *r) - int i, chunks = 3, error_bucket = 1; - size_t chunk_size = sizeof(buffer); - const char *request_id = "none"; -- apr_time_t delay = 0, chunk_delay = 0; -+ apr_time_t delay = 0, chunk_delay = 0, close_delay = 0; - apr_array_header_t *args = NULL; - int http_status = 200; - apr_status_t error = APR_SUCCESS, body_error = APR_SUCCESS; -+ int close_conn = 0, with_cl = 0; - - if(strcmp(r->handler, "curltest-tweak")) { - return DECLINED; - } -- if(r->method_number != M_GET && r->method_number != M_POST) { -+ if(r->method_number == M_DELETE) { -+ http_status = 204; -+ chunks = 0; -+ } -+ else if(r->method_number != M_GET && r->method_number != M_POST) { - return DECLINED; - } - - if(r->args) { - args = apr_cstr_split(r->args, "&", 1, r->pool); - for(i = 0; i < args->nelts; ++i) { -- char *s, *val, *arg = APR_ARRAY_IDX(args, i, char*); -+ char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *); - s = strchr(arg, '='); - if(s) { - *s = '\0'; -@@ -334,6 +412,21 @@ static int curltest_tweak_handler(request_rec *r) - continue; - } - } -+ else if(!strcmp("close_delay", arg)) { -+ rv = duration_parse(&close_delay, val, "s"); -+ if(APR_SUCCESS == rv) { -+ continue; -+ } -+ } -+ } -+ else if(!strcmp("close", arg)) { -+ /* we are asked to close the connection */ -+ close_conn = 1; -+ continue; -+ } -+ else if(!strcmp("with_cl", arg)) { -+ with_cl = 1; -+ continue; - } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not " - "understood: '%s' in %s", -@@ -346,10 +439,15 @@ static int curltest_tweak_handler(request_rec *r) - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "error_handler: processing " - "request, %s", r->args? r->args : "(no args)"); - r->status = http_status; -- r->clength = -1; -- r->chunked = (r->proto_num >= HTTP_VERSION(1,1)); -+ r->clength = with_cl ? (chunks * chunk_size) : -1; -+ r->chunked = (r->proto_num >= HTTP_VERSION(1, 1)) && !with_cl; - apr_table_setn(r->headers_out, "request-id", request_id); -- apr_table_unset(r->headers_out, "Content-Length"); -+ if(r->clength >= 0) { -+ apr_table_set(r->headers_out, "Content-Length", -+ apr_ltoa(r->pool, (long)r->clength)); -+ } -+ else -+ apr_table_unset(r->headers_out, "Content-Length"); - /* Discourage content-encodings */ - apr_table_unset(r->headers_out, "Content-Encoding"); - apr_table_setn(r->subprocess_env, "no-brotli", "1"); -@@ -368,7 +466,8 @@ static int curltest_tweak_handler(request_rec *r) - b = apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, b); - rv = ap_pass_brigade(r->output_filters, bb); -- if (APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - - memset(buffer, 'X', sizeof(buffer)); - for(i = 0; i < chunks; ++i) { -@@ -376,9 +475,11 @@ static int curltest_tweak_handler(request_rec *r) - apr_sleep(chunk_delay); - } - rv = apr_brigade_write(bb, NULL, NULL, buffer, chunk_size); -- if(APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - rv = ap_pass_brigade(r->output_filters, bb); -- if(APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, - "error_handler: passed %lu bytes as response body", - (unsigned long)chunk_size); -@@ -396,9 +497,19 @@ static int curltest_tweak_handler(request_rec *r) - "error_handler: response passed"); - - cleanup: -+ if(close_conn) { -+ if(close_delay) { -+ b = apr_bucket_flush_create(c->bucket_alloc); -+ APR_BRIGADE_INSERT_TAIL(bb, b); -+ rv = ap_pass_brigade(r->output_filters, bb); -+ apr_brigade_cleanup(bb); -+ apr_sleep(close_delay); -+ } -+ r->connection->keepalive = AP_CONN_CLOSE; -+ } - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, -- "error_handler: request cleanup, r->status=%d, aborted=%d", -- r->status, c->aborted); -+ "error_handler: request cleanup, r->status=%d, aborted=%d, " -+ "close=%d", r->status, c->aborted, close_conn); - if(rv == APR_SUCCESS) { - return OK; - } -@@ -420,9 +531,10 @@ static int curltest_put_handler(request_rec *r) - apr_bucket_brigade *bb; - apr_bucket *b; - apr_status_t rv; -- char buffer[16*1024]; -+ char buffer[128*1024]; - const char *ct; - apr_off_t rbody_len = 0; -+ apr_off_t rbody_max_len = -1; - const char *s_rbody_len; - const char *request_id = "none"; - apr_time_t read_delay = 0, chunk_delay = 0; -@@ -440,7 +552,7 @@ static int curltest_put_handler(request_rec *r) - if(r->args) { - args = apr_cstr_split(r->args, "&", 1, r->pool); - for(i = 0; i < args->nelts; ++i) { -- char *s, *val, *arg = APR_ARRAY_IDX(args, i, char*); -+ char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *); - s = strchr(arg, '='); - if(s) { - *s = '\0'; -@@ -462,6 +574,10 @@ static int curltest_put_handler(request_rec *r) - continue; - } - } -+ else if(!strcmp("max_upload", arg)) { -+ rbody_max_len = (int)apr_atoi64(val); -+ continue; -+ } - } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not " - "understood: '%s' in %s", -@@ -482,14 +598,16 @@ static int curltest_put_handler(request_rec *r) - apr_table_setn(r->subprocess_env, "no-gzip", "1"); - - ct = apr_table_get(r->headers_in, "content-type"); -- ap_set_content_type(r, ct? ct : "text/plain"); -+ ap_set_content_type(r, ct ? ct : "text/plain"); - - if(read_delay) { - apr_sleep(read_delay); - } - bb = apr_brigade_create(r->pool, c->bucket_alloc); - /* copy any request body into the response */ -- if((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) goto cleanup; -+ rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); -+ if(rv) -+ goto cleanup; - if(ap_should_client_block(r)) { - while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) { - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, -@@ -498,19 +616,28 @@ static int curltest_put_handler(request_rec *r) - apr_sleep(chunk_delay); - } - rbody_len += l; -+ if((rbody_max_len > 0) && (rbody_len > rbody_max_len)) { -+ r->status = 413; -+ break; -+ } - } - } - /* we are done */ - s_rbody_len = apr_psprintf(r->pool, "%"APR_OFF_T_FMT, rbody_len); - apr_table_setn(r->headers_out, "Received-Length", s_rbody_len); - rv = apr_brigade_puts(bb, NULL, NULL, s_rbody_len); -- if(APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - b = apr_bucket_eos_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "put_handler: request read"); - - rv = ap_pass_brigade(r->output_filters, bb); - -+ if(r->status == 413) { -+ apr_sleep(apr_time_from_sec(1)); -+ } -+ - cleanup: - if(rv == APR_SUCCESS - || r->status != HTTP_OK -@@ -544,7 +671,7 @@ static int curltest_1_1_required(request_rec *r) - return DECLINED; - } - -- if (HTTP_VERSION_MAJOR(r->proto_num) > 1) { -+ if(HTTP_VERSION_MAJOR(r->proto_num) > 1) { - apr_table_setn(r->notes, "ssl-renegotiate-forbidden", "1"); - ap_die(HTTP_FORBIDDEN, r); - return OK; -@@ -561,18 +688,130 @@ static int curltest_1_1_required(request_rec *r) - apr_table_setn(r->subprocess_env, "no-gzip", "1"); - - ct = apr_table_get(r->headers_in, "content-type"); -- ap_set_content_type(r, ct? ct : "text/plain"); -+ ap_set_content_type(r, ct ? ct : "text/plain"); - - bb = apr_brigade_create(r->pool, c->bucket_alloc); - /* flush response */ - b = apr_bucket_flush_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, b); - rv = ap_pass_brigade(r->output_filters, bb); -- if (APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; - - /* we are done */ - rv = apr_brigade_printf(bb, NULL, NULL, "well done!"); -- if(APR_SUCCESS != rv) goto cleanup; -+ if(APR_SUCCESS != rv) -+ goto cleanup; -+ b = apr_bucket_eos_create(c->bucket_alloc); -+ APR_BRIGADE_INSERT_TAIL(bb, b); -+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "1_1_handler: request read"); -+ -+ rv = ap_pass_brigade(r->output_filters, bb); -+ -+cleanup: -+ if(rv == APR_SUCCESS -+ || r->status != HTTP_OK -+ || c->aborted) { -+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler: done"); -+ return OK; -+ } -+ else { -+ /* no way to know what type of error occurred */ -+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, "1_1_handler failed"); -+ return AP_FILTER_ERROR; -+ } -+ return DECLINED; -+} -+ -+static int brigade_env_var(request_rec *r, apr_bucket_brigade *bb, -+ const char *name) -+{ -+ const char *s; -+ s = apr_table_get(r->subprocess_env, name); -+ if(s) -+ return apr_brigade_printf(bb, NULL, NULL, ",\n \"%s\": \"%s\"", name, s); -+ return 0; -+} -+ -+static int curltest_sslinfo_handler(request_rec *r) -+{ -+ conn_rec *c = r->connection; -+ apr_bucket_brigade *bb; -+ apr_bucket *b; -+ apr_status_t rv; -+ apr_array_header_t *args = NULL; -+ const char *request_id = NULL; -+ int close_conn = 0; -+ long l; -+ int i; -+ -+ if(strcmp(r->handler, "curltest-sslinfo")) { -+ return DECLINED; -+ } -+ if(r->method_number != M_GET) { -+ return DECLINED; -+ } -+ -+ if(r->args) { -+ apr_array_header_t *args = apr_cstr_split(r->args, "&", 1, r->pool); -+ for(i = 0; i < args->nelts; ++i) { -+ char *s, *val, *arg = APR_ARRAY_IDX(args, i, char *); -+ s = strchr(arg, '='); -+ if(s) { -+ *s = '\0'; -+ val = s + 1; -+ if(!strcmp("id", arg)) { -+ /* just an id for repeated requests with curl's url globbing */ -+ request_id = val; -+ continue; -+ } -+ } -+ else if(!strcmp("close", arg)) { -+ /* we are asked to close the connection */ -+ close_conn = 1; -+ continue; -+ } -+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not " -+ "understood: '%s' in %s", -+ arg, r->args); -+ ap_die(HTTP_BAD_REQUEST, r); -+ return OK; -+ } -+ } -+ -+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "sslinfo: processing"); -+ r->status = 200; -+ r->clength = -1; -+ r->chunked = 1; -+ apr_table_unset(r->headers_out, "Content-Length"); -+ /* Discourage content-encodings */ -+ apr_table_unset(r->headers_out, "Content-Encoding"); -+ apr_table_setn(r->subprocess_env, "no-brotli", "1"); -+ apr_table_setn(r->subprocess_env, "no-gzip", "1"); -+ -+ ap_set_content_type(r, "application/json"); -+ -+ bb = apr_brigade_create(r->pool, c->bucket_alloc); -+ -+ apr_brigade_puts(bb, NULL, NULL, "{\n \"Name\": \"SSL-Information\""); -+ brigade_env_var(r, bb, "HTTPS"); -+ brigade_env_var(r, bb, "SSL_PROTOCOL"); -+ brigade_env_var(r, bb, "SSL_CIPHER"); -+ brigade_env_var(r, bb, "SSL_SESSION_ID"); -+ brigade_env_var(r, bb, "SSL_SESSION_RESUMED"); -+ brigade_env_var(r, bb, "SSL_SRP_USER"); -+ brigade_env_var(r, bb, "SSL_SRP_USERINFO"); -+ brigade_env_var(r, bb, "SSL_TLS_SNI"); -+ apr_brigade_puts(bb, NULL, NULL, "}\n"); -+ -+ /* flush response */ -+ b = apr_bucket_flush_create(c->bucket_alloc); -+ APR_BRIGADE_INSERT_TAIL(bb, b); -+ rv = ap_pass_brigade(r->output_filters, bb); -+ if(APR_SUCCESS != rv) -+ goto cleanup; -+ -+ /* we are done */ - b = apr_bucket_eos_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, b); - ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "1_1_handler: request read"); -@@ -580,6 +819,8 @@ static int curltest_1_1_required(request_rec *r) - rv = ap_pass_brigade(r->output_filters, bb); - - cleanup: -+ if(close_conn) -+ r->connection->keepalive = AP_CONN_CLOSE; - if(rv == APR_SUCCESS - || r->status != HTTP_OK - || c->aborted) { -diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py -index 9544ce05d..801d9a63a 100644 ---- a/tests/http/testenv/nghttpx.py -+++ b/tests/http/testenv/nghttpx.py -@@ -41,10 +41,11 @@ log = logging.getLogger(__name__) - - class Nghttpx: - -- def __init__(self, env: Env, port: int, name: str): -+ def __init__(self, env: Env, port: int, https_port: int, name: str): - self.env = env - self._name = name - self._port = port -+ self._https_port = https_port - self._cmd = env.nghttpx - self._run_dir = os.path.join(env.gen_dir, name) - self._pid_file = os.path.join(self._run_dir, 'nghttpx.pid') -@@ -52,15 +53,18 @@ class Nghttpx: - self._error_log = os.path.join(self._run_dir, 'nghttpx.log') - self._stderr = os.path.join(self._run_dir, 'nghttpx.stderr') - self._tmp_dir = os.path.join(self._run_dir, 'tmp') -- self._process = None - self._process: Optional[subprocess.Popen] = None - self._rmf(self._pid_file) - self._rmf(self._error_log) - self._mkpath(self._run_dir) - self._write_config() - -+ @property -+ def https_port(self): -+ return self._https_port -+ - def exists(self): -- return os.path.exists(self._cmd) -+ return self._cmd and os.path.exists(self._cmd) - - def clear_logs(self): - self._rmf(self._error_log) -@@ -128,10 +132,18 @@ class Nghttpx: - curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: -- check_url = f'https://{self.env.domain1}:{self._port}/' -- r = curl.http_get(url=check_url, extra_args=[ -- '--http3-only', '--connect-timeout', '1' -- ]) -+ if self._https_port > 0: -+ check_url = f'https://{self.env.domain1}:{self._https_port}/' -+ r = curl.http_get(url=check_url, extra_args=[ -+ '--trace', 'curl.trace', '--trace-time', -+ '--connect-timeout', '1' -+ ]) -+ else: -+ check_url = f'https://{self.env.domain1}:{self._port}/' -+ r = curl.http_get(url=check_url, extra_args=[ -+ '--trace', 'curl.trace', '--trace-time', -+ '--http3-only', '--connect-timeout', '1' -+ ]) - if r.exit_code != 0: - return True - log.debug(f'waiting for nghttpx to stop responding: {r}') -@@ -143,11 +155,18 @@ class Nghttpx: - curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: -- check_url = f'https://{self.env.domain1}:{self._port}/' -- r = curl.http_get(url=check_url, extra_args=[ -- '--http3-only', '--trace', 'curl.trace', '--trace-time', -- '--connect-timeout', '1' -- ]) -+ if self._https_port > 0: -+ check_url = f'https://{self.env.domain1}:{self._https_port}/' -+ r = curl.http_get(url=check_url, extra_args=[ -+ '--trace', 'curl.trace', '--trace-time', -+ '--connect-timeout', '1' -+ ]) -+ else: -+ check_url = f'https://{self.env.domain1}:{self._port}/' -+ r = curl.http_get(url=check_url, extra_args=[ -+ '--http3-only', '--trace', 'curl.trace', '--trace-time', -+ '--connect-timeout', '1' -+ ]) - if r.exit_code == 0: - return True - log.debug(f'waiting for nghttpx to become responsive: {r}') -@@ -165,7 +184,7 @@ class Nghttpx: - - def _write_config(self): - with open(self._conf_file, 'w') as fd: -- fd.write(f'# nghttpx test config'), -+ fd.write('# nghttpx test config') - fd.write("\n".join([ - '# do we need something here?' - ])) -@@ -174,28 +193,32 @@ class Nghttpx: - class NghttpxQuic(Nghttpx): - - def __init__(self, env: Env): -- super().__init__(env=env, name='nghttpx-quic', port=env.h3_port) -+ super().__init__(env=env, name='nghttpx-quic', port=env.h3_port, -+ https_port=env.nghttpx_https_port) - - def start(self, wait_live=True): - self._mkpath(self._tmp_dir) - if self._process: - self.stop() -+ creds = self.env.get_credentials(self.env.domain1) -+ assert creds # convince pytype this isn't None - args = [ - self._cmd, - f'--frontend=*,{self.env.h3_port};quic', -+ f'--frontend=*,{self.env.nghttpx_https_port};tls', - f'--backend=127.0.0.1,{self.env.https_port};{self.env.domain1};sni={self.env.domain1};proto=h2;tls', - f'--backend=127.0.0.1,{self.env.http_port}', -- f'--log-level=INFO', -+ '--log-level=INFO', - f'--pid-file={self._pid_file}', - f'--errorlog-file={self._error_log}', - f'--conf={self._conf_file}', - f'--cacert={self.env.ca.cert_file}', -- self.env.get_credentials(self.env.domain1).pkey_file, -- self.env.get_credentials(self.env.domain1).cert_file, -- f'--frontend-http3-window-size=1M', -- f'--frontend-http3-max-window-size=10M', -- f'--frontend-http3-connection-window-size=10M', -- f'--frontend-http3-max-connection-window-size=100M', -+ creds.pkey_file, -+ creds.cert_file, -+ '--frontend-http3-window-size=1M', -+ '--frontend-http3-max-window-size=10M', -+ '--frontend-http3-connection-window-size=10M', -+ '--frontend-http3-max-connection-window-size=100M', - # f'--frontend-quic-debug-log', - ] - ngerr = open(self._stderr, 'a') -@@ -208,24 +231,27 @@ class NghttpxQuic(Nghttpx): - class NghttpxFwd(Nghttpx): - - def __init__(self, env: Env): -- super().__init__(env=env, name='nghttpx-fwd', port=env.h2proxys_port) -+ super().__init__(env=env, name='nghttpx-fwd', port=env.h2proxys_port, -+ https_port=0) - - def start(self, wait_live=True): - self._mkpath(self._tmp_dir) - if self._process: - self.stop() -+ creds = self.env.get_credentials(self.env.proxy_domain) -+ assert creds # convince pytype this isn't None - args = [ - self._cmd, -- f'--http2-proxy', -+ '--http2-proxy', - f'--frontend=*,{self.env.h2proxys_port}', - f'--backend=127.0.0.1,{self.env.proxy_port}', -- f'--log-level=INFO', -+ '--log-level=INFO', - f'--pid-file={self._pid_file}', - f'--errorlog-file={self._error_log}', - f'--conf={self._conf_file}', - f'--cacert={self.env.ca.cert_file}', -- self.env.get_credentials(self.env.proxy_domain).pkey_file, -- self.env.get_credentials(self.env.proxy_domain).cert_file, -+ creds.pkey_file, -+ creds.cert_file, - ] - ngerr = open(self._stderr, 'a') - self._process = subprocess.Popen(args=args, stderr=ngerr) -diff --git a/tests/http/testenv/vsftpd.py b/tests/http/testenv/vsftpd.py -new file mode 100644 -index 000000000..5f4f0c064 ---- /dev/null -+++ b/tests/http/testenv/vsftpd.py -@@ -0,0 +1,197 @@ -+#!/usr/bin/env python3 -+# -*- coding: utf-8 -*- -+#*************************************************************************** -+# _ _ ____ _ -+# Project ___| | | | _ \| | -+# / __| | | | |_) | | -+# | (__| |_| | _ <| |___ -+# \___|\___/|_| \_\_____| -+# -+# Copyright (C) Daniel Stenberg, , 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 logging -+import os -+import subprocess -+import time -+ -+from datetime import datetime, timedelta -+ -+from .curl import CurlClient -+from .env import Env -+ -+ -+log = logging.getLogger(__name__) -+ -+ -+class VsFTPD: -+ -+ def __init__(self, env: Env, with_ssl=False): -+ self.env = env -+ self._cmd = env.vsftpd -+ self._scheme = 'ftp' -+ self._with_ssl = with_ssl -+ if self._with_ssl: -+ self._port = self.env.ftps_port -+ name = 'vsftpds' -+ else: -+ self._port = self.env.ftp_port -+ name = 'vsftpd' -+ self._vsftpd_dir = os.path.join(env.gen_dir, name) -+ self._run_dir = os.path.join(self._vsftpd_dir, 'run') -+ self._docs_dir = os.path.join(self._vsftpd_dir, 'docs') -+ self._tmp_dir = os.path.join(self._vsftpd_dir, 'tmp') -+ self._conf_file = os.path.join(self._vsftpd_dir, 'test.conf') -+ self._pid_file = os.path.join(self._vsftpd_dir, 'vsftpd.pid') -+ self._error_log = os.path.join(self._vsftpd_dir, 'vsftpd.log') -+ self._process = None -+ -+ self.clear_logs() -+ -+ @property -+ def domain(self): -+ return self.env.ftp_domain -+ -+ @property -+ def docs_dir(self): -+ return self._docs_dir -+ -+ @property -+ def port(self) -> int: -+ return self._port -+ -+ def clear_logs(self): -+ self._rmf(self._error_log) -+ -+ def exists(self): -+ return os.path.exists(self._cmd) -+ -+ def is_running(self): -+ if self._process: -+ self._process.poll() -+ return self._process.returncode is None -+ return False -+ -+ def start_if_needed(self): -+ if not self.is_running(): -+ return self.start() -+ return True -+ -+ def stop_if_running(self): -+ if self.is_running(): -+ return self.stop() -+ return True -+ -+ def stop(self, wait_dead=True): -+ self._mkpath(self._tmp_dir) -+ if self._process: -+ self._process.terminate() -+ self._process.wait(timeout=2) -+ self._process = None -+ return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5)) -+ return True -+ -+ def restart(self): -+ self.stop() -+ return self.start() -+ -+ def start(self, wait_live=True): -+ self._mkpath(self._tmp_dir) -+ if self._process: -+ self.stop() -+ self._write_config() -+ args = [ -+ self._cmd, -+ f'{self._conf_file}', -+ ] -+ procerr = open(self._error_log, 'a') -+ self._process = subprocess.Popen(args=args, stderr=procerr) -+ if self._process.returncode is not None: -+ return False -+ return not wait_live or self.wait_live(timeout=timedelta(seconds=5)) -+ -+ def wait_dead(self, timeout: timedelta): -+ curl = CurlClient(env=self.env, run_dir=self._tmp_dir) -+ try_until = datetime.now() + timeout -+ while datetime.now() < try_until: -+ check_url = f'{self._scheme}://{self.domain}:{self.port}/' -+ r = curl.ftp_get(urls=[check_url], extra_args=['-v']) -+ if r.exit_code != 0: -+ return True -+ log.debug(f'waiting for vsftpd to stop responding: {r}') -+ time.sleep(.1) -+ log.debug(f"Server still responding after {timeout}") -+ return False -+ -+ def wait_live(self, timeout: timedelta): -+ curl = CurlClient(env=self.env, run_dir=self._tmp_dir) -+ try_until = datetime.now() + timeout -+ while datetime.now() < try_until: -+ check_url = f'{self._scheme}://{self.domain}:{self.port}/' -+ r = curl.ftp_get(urls=[check_url], extra_args=[ -+ '--trace', 'curl-start.trace', '--trace-time' -+ ]) -+ if r.exit_code == 0: -+ return True -+ log.debug(f'waiting for vsftpd to become responsive: {r}') -+ time.sleep(.1) -+ log.error(f"Server still not responding after {timeout}") -+ return False -+ -+ def _rmf(self, path): -+ if os.path.exists(path): -+ return os.remove(path) -+ -+ def _mkpath(self, path): -+ if not os.path.exists(path): -+ return os.makedirs(path) -+ -+ def _write_config(self): -+ self._mkpath(self._docs_dir) -+ self._mkpath(self._tmp_dir) -+ conf = [ # base server config -+ 'listen=YES', -+ 'run_as_launching_user=YES', -+ '#listen_address=127.0.0.1', -+ f'listen_port={self.port}', -+ 'local_enable=NO', -+ 'anonymous_enable=YES', -+ f'anon_root={self._docs_dir}', -+ 'dirmessage_enable=YES', -+ 'write_enable=YES', -+ 'anon_upload_enable=YES', -+ 'log_ftp_protocol=YES', -+ 'xferlog_enable=YES', -+ 'xferlog_std_format=NO', -+ f'vsftpd_log_file={self._error_log}', -+ '\n', -+ ] -+ if self._with_ssl: -+ creds = self.env.get_credentials(self.domain) -+ assert creds # convince pytype this isn't None -+ conf.extend([ -+ 'ssl_enable=YES', -+ 'debug_ssl=YES', -+ 'allow_anon_ssl=YES', -+ f'rsa_cert_file={creds.cert_file}', -+ f'rsa_private_key_file={creds.pkey_file}', -+ # require_ssl_reuse=YES means ctrl and data connection need to use the same session -+ 'require_ssl_reuse=NO', -+ ]) -+ -+ with open(self._conf_file, 'w') as fd: -+ fd.write("\n".join(conf)) -diff --git a/tests/http/testenv/ws_echo_server.py b/tests/http/testenv/ws_echo_server.py -index d13f757c7..99eaa628d 100755 ---- a/tests/http/testenv/ws_echo_server.py -+++ b/tests/http/testenv/ws_echo_server.py -@@ -27,7 +27,6 @@ - import argparse - import asyncio - import logging --from asyncio import IncompleteReadError - - from websockets import server - from websockets.exceptions import ConnectionClosedError -diff --git a/tests/http2-server.pl b/tests/http2-server.pl -index 52c5284c0..fef17680a 100755 ---- a/tests/http2-server.pl -+++ b/tests/http2-server.pl -@@ -38,6 +38,7 @@ my $listenport2 = 9016; - my $connect = "127.0.0.1,8990"; - my $conf = "nghttpx.conf"; - my $cert = "Server-localhost-sv"; -+my $dev_null = ($^O eq 'MSWin32' ? 'NUL' : '/dev/null'); - - #*************************************************************************** - # Process command line options -@@ -108,6 +109,7 @@ $certfile = abs_path($certfile); - $keyfile = abs_path($keyfile); - - my $cmdline="$nghttpx --backend=$connect ". -+ "--backend-keep-alive-timeout=500ms ". - "--frontend=\"*,$listenport;no-tls\" ". - "--frontend=\"*,$listenport2\" ". - "--log-level=INFO ". -@@ -116,4 +118,4 @@ my $cmdline="$nghttpx --backend=$connect ". - "--errorlog-file=$logfile ". - "$keyfile $certfile"; - print "RUN: $cmdline\n" if($verbose); --system("$cmdline 2>/dev/null"); -+exec("exec $cmdline 2>$dev_null"); -diff --git a/tests/http3-server.pl b/tests/http3-server.pl -index bc9e98ad1..489053c19 100755 ---- a/tests/http3-server.pl -+++ b/tests/http3-server.pl -@@ -38,6 +38,7 @@ my $listenport = 9017; - my $connect = "127.0.0.1,8990"; - my $cert = "Server-localhost-sv"; - my $conf = "nghttpx.conf"; -+my $dev_null = ($^O eq 'MSWin32' ? 'NUL' : '/dev/null'); - - #*************************************************************************** - # Process command line options -@@ -108,6 +109,7 @@ $certfile = abs_path($certfile); - $keyfile = abs_path($keyfile); - - my $cmdline="$nghttpx --http2-proxy --backend=$connect ". -+ "--backend-keep-alive-timeout=500ms ". - "--frontend=\"*,$listenport\" ". - "--frontend=\"*,$listenport;quic\" ". - "--log-level=INFO ". -@@ -116,4 +118,4 @@ my $cmdline="$nghttpx --http2-proxy --backend=$connect ". - "--conf=$conf ". - "$keyfile $certfile"; - print "RUN: $cmdline\n" if($verbose); --system("$cmdline 2>/dev/null"); -+exec("exec $cmdline 2>$dev_null"); -diff --git a/tests/libtest/.gitignore b/tests/libtest/.gitignore -index 9541d16e1..9fd1a098c 100644 ---- a/tests/libtest/.gitignore -+++ b/tests/libtest/.gitignore -@@ -2,10 +2,10 @@ - # - # SPDX-License-Identifier: curl - --chkhostname - lib[1234][0-9][0-9][0-9] - lib[56][0-9][0-9] - lib1521.c -+libtests.c - libauthretry - libntlmconnect - libprereq -diff --git a/tests/libtest/CMakeLists.txt b/tests/libtest/CMakeLists.txt -index b6450ff3a..d60f7a331 100644 ---- a/tests/libtest/CMakeLists.txt -+++ b/tests/libtest/CMakeLists.txt -@@ -21,68 +21,66 @@ - # SPDX-License-Identifier: curl - # - ########################################################################### --set(TARGET_LABEL_PREFIX "Test ") - --function(setup_test TEST_NAME) # ARGN are the files in the test -- -- if(LIB_SELECTED STREQUAL LIB_STATIC) -- # These are part of the libcurl static lib. Do not compile/link them again. -- list(REMOVE_ITEM ARGN ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF}) -- endif() -- -- add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN}) -- add_dependencies(testdeps ${TEST_NAME}) -- string(TOUPPER ${TEST_NAME} UPPER_TEST_NAME) -- -- include_directories( -- ${CURL_SOURCE_DIR}/lib # To be able to reach "curl_setup_once.h" -- ${CURL_BINARY_DIR}/lib # To be able to reach "curl_config.h" -- ${CURL_BINARY_DIR}/include # To be able to reach "curl/curl.h" -- ${CURL_SOURCE_DIR}/tests/libtest # To be able to build generated tests -- ) -- if(USE_ARES) -- include_directories(${CARES_INCLUDE_DIR}) -- endif() -+# Get 'LIBTESTPROGS', '*_SOURCES', 'TESTUTIL', 'TSTTRACE', 'WARNLESS', 'MULTIBYTE', 'TIMEDIFF', 'THREADS', 'FIRSTFILES' variables -+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") -+include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") - -- target_link_libraries(${TEST_NAME} ${LIB_SELECTED} ${CURL_LIBS}) -+set_source_files_properties("../../lib/curl_multibyte.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON) - -- set_target_properties(${TEST_NAME} -- PROPERTIES COMPILE_DEFINITIONS ${UPPER_TEST_NAME}) -- set_target_properties(${TEST_NAME} -- PROPERTIES PROJECT_LABEL "${TARGET_LABEL_PREFIX}${TEST_NAME}") --endfunction() -+add_custom_command( -+ OUTPUT "lib1521.c" -+ COMMAND ${PERL_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl" < "${PROJECT_SOURCE_DIR}/include/curl/curl.h" "lib1521.c" -+ DEPENDS -+ "${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl" -+ "${PROJECT_SOURCE_DIR}/include/curl/curl.h" -+ VERBATIM) - -+if(CURL_TEST_BUNDLES) -+ add_custom_command( -+ OUTPUT "libtest_bundle.c" -+ COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/tests/mk-bundle.pl" "${CMAKE_CURRENT_SOURCE_DIR}" > "libtest_bundle.c" -+ DEPENDS -+ "${PROJECT_SOURCE_DIR}/tests/mk-bundle.pl" ${FIRSTFILES} "lib1521.c" -+ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.inc" -+ VERBATIM) - --transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake") --include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake) -+ set(LIBTESTPROGS "libtests") -+ set(libtests_SOURCES "libtest_bundle.c") -+ list(APPEND libtests_SOURCES ${TESTUTIL} ${TSTTRACE}) -+ if(LIB_SELECTED STREQUAL LIB_SHARED) -+ # These are part of the libcurl static lib. Add them here when linking shared. -+ list(APPEND libtests_SOURCES ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF} ${THREADS}) -+ endif() -+endif() - --foreach(TEST_NAME ${noinst_PROGRAMS}) -- if(DEFINED ${TEST_NAME}_SOURCES) -- setup_test(${TEST_NAME} ${${TEST_NAME}_SOURCES}) -+foreach(_target IN LISTS LIBTESTPROGS) -+ if(DEFINED ${_target}_SOURCES) -+ set(_sources ${${_target}_SOURCES}) - else() -- setup_test(${TEST_NAME} ${nodist_${TEST_NAME}_SOURCES}) -+ set(_sources ${nodist_${_target}_SOURCES}) - endif() --endforeach() - --# Allows for hostname override to make tests machine independent. --# TODO this cmake build assumes a shared build, detect static linking here! --if(NOT WIN32) -- add_library(hostname MODULE EXCLUDE_FROM_ALL sethostname.c) -- add_dependencies(testdeps hostname) -- # Output to .libs for compatibility with autotools, the test data expects a -- # library at (tests)/libtest/.libs/libhostname.so -- set_target_properties(hostname PROPERTIES -- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.libs) -- if(HIDES_CURL_PRIVATE_SYMBOLS) -- set_property(TARGET hostname APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") -- set_property(TARGET hostname APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) -+ if(LIB_SELECTED STREQUAL LIB_STATIC) -+ # These are part of the libcurl static lib. Do not compile/link them again. -+ list(REMOVE_ITEM _sources ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF} ${THREADS}) - endif() --endif() - --add_custom_command( -- OUTPUT lib1521.c -- COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl < ${CURL_SOURCE_DIR}/include/curl/curl.h > lib1521.c -- DEPENDS -- "${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl" -- "${CURL_SOURCE_DIR}/include/curl/curl.h" -- VERBATIM) -+ string(TOUPPER ${_target} _upper_target) -+ set(_target_name "${_target}") -+ add_executable(${_target_name} EXCLUDE_FROM_ALL ${_sources}) -+ add_dependencies(testdeps ${_target_name}) -+ target_link_libraries(${_target_name} ${LIB_SELECTED} ${CURL_LIBS}) -+ target_include_directories(${_target_name} PRIVATE -+ "${PROJECT_BINARY_DIR}/lib" # for "curl_config.h" -+ "${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h" -+ "${PROJECT_SOURCE_DIR}/tests/libtest" # to be able to build generated tests -+ ) -+ if(NOT CURL_TEST_BUNDLES) -+ set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS ${_upper_target}) -+ endif() -+ set_property(TARGET ${_target_name} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_NO_GETADDRINFO_OVERRIDE") -+ set_target_properties(${_target_name} PROPERTIES -+ OUTPUT_NAME "${_target}" -+ PROJECT_LABEL "Test libtest ${_target}") -+endforeach() -diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am -index 8ae972a24..809731d07 100644 ---- a/tests/libtest/Makefile.am -+++ b/tests/libtest/Makefile.am -@@ -34,10 +34,11 @@ AUTOMAKE_OPTIONS = foreign nostdinc - - AM_CPPFLAGS = -I$(top_srcdir)/include \ - -I$(top_builddir)/lib \ -- -I$(top_srcdir)/lib -+ -I$(top_srcdir)/lib \ -+ -I$(top_srcdir)/tests/libtest - - EXTRA_DIST = test307.pl test610.pl test613.pl test1013.pl test1022.pl \ -- Makefile.inc notexists.pl CMakeLists.txt mk-lib1521.pl .checksrc -+ CMakeLists.txt mk-lib1521.pl .checksrc - - CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@ - -@@ -48,29 +49,17 @@ CLEANFILES = lib1521.c - # Prevent LIBS from being used for all link targets - LIBS = $(BLANK_AT_MAKETIME) - --if USE_EXPLICIT_LIB_DEPS --SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ --TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ --else --SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ --TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ --endif -+SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@ -+TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@ - - # Dependencies (may need to be overridden) - LDADD = $(SUPPORTFILES_LIBS) - - # Makefile.inc provides the source defines (TESTUTIL, SUPPORTFILES, --# noinst_PROGRAMS, lib*_SOURCES, and lib*_CFLAGS) -+# LIBTESTPROGS, lib*_SOURCES, and lib*_CFLAGS) - include Makefile.inc - --# Preloading of libhostname allows host name overriding, --# this is used to make some tests machine independent. -- --if BUILD_LIBHOSTNAME --noinst_LTLIBRARIES = libhostname.la --else - noinst_LTLIBRARIES = --endif - - if USE_CPPFLAG_CURL_STATICLIB - AM_CPPFLAGS += -DCURL_STATICLIB -@@ -79,35 +68,12 @@ endif - AM_LDFLAGS = - AM_CFLAGS = - --libhostname_la_CPPFLAGS_EXTRA = --libhostname_la_LDFLAGS_EXTRA = -module -avoid-version -rpath /nowhere --libhostname_la_CFLAGS_EXTRA = -- - libstubgss_la_LDFLAGS_EXTRA = - - if CURL_LT_SHLIB_USE_NO_UNDEFINED --libhostname_la_LDFLAGS_EXTRA += -no-undefined - libstubgss_la_LDFLAGS_EXTRA += -no-undefined - endif - --if CURL_LT_SHLIB_USE_MIMPURE_TEXT --libhostname_la_LDFLAGS_EXTRA += -mimpure-text --endif -- --if DOING_CURL_SYMBOL_HIDING --libhostname_la_CPPFLAGS_EXTRA += -DCURL_HIDDEN_SYMBOLS --libhostname_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) --endif -- --libhostname_la_CPPFLAGS = $(AM_CPPFLAGS) $(libhostname_la_CPPFLAGS_EXTRA) --libhostname_la_LDFLAGS = $(AM_LDFLAGS) $(libhostname_la_LDFLAGS_EXTRA) --libhostname_la_CFLAGS = $(AM_CFLAGS) $(libhostname_la_CFLAGS_EXTRA) -- --libhostname_la_SOURCES = sethostname.c -- --libhostname_la_LIBADD = --libhostname_la_DEPENDENCIES = -- - # Build a stub gssapi implementation for testing - if BUILD_STUB_GSS - noinst_LTLIBRARIES += libstubgss.la -@@ -122,9 +88,29 @@ libstubgss_la_LIBADD = - libstubgss_la_DEPENDENCIES = - endif - -+if USE_TEST_BUNDLES -+AM_CPPFLAGS += -DCURL_NO_GETADDRINFO_OVERRIDE -+ -+libtest_bundle.c: $(top_srcdir)/tests/mk-bundle.pl lib1521.c -+ @PERL@ $(top_srcdir)/tests/mk-bundle.pl $(srcdir) > libtest_bundle.c -+ -+noinst_PROGRAMS = libtests -+nodist_libtests_SOURCES = libtest_bundle.c -+libtests_SOURCES = $(TESTUTIL) $(TSTTRACE) -+libtests_LDADD = $(TESTUTIL_LIBS) -+CLEANFILES += libtest_bundle.c -+ -+if USE_CPPFLAG_CURL_STATICLIB -+else -+# These are part of the libcurl static lib. Add them here when linking shared. -+libtests_SOURCES += $(WARNLESS) $(MULTIBYTE) $(TIMEDIFF) $(THREADS) -+endif -+else -+noinst_PROGRAMS = $(LIBTESTPROGS) -+endif - - lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/curl.h -- @PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h > lib1521.c -+ @PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h lib1521.c - - CHECKSRC = $(CS_$(V)) - CS_0 = @echo " RUN " $@; -@@ -134,7 +120,7 @@ CS_ = $(CS_0) - checksrc: - $(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/*.[ch] - --if CURLDEBUG -+if DEBUGBUILD - # for debug builds, we scan the sources on all regular make invokes - all-local: checksrc - endif -diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc -index 9f7cec602..339a00fc4 100644 ---- a/tests/libtest/Makefile.inc -+++ b/tests/libtest/Makefile.inc -@@ -35,10 +35,13 @@ MULTIBYTE = ../../lib/curl_multibyte.c ../../lib/curl_multibyte.h - - # these files are used in every single test program below - TIMEDIFF = ../../lib/timediff.c ../../lib/timediff.h --SUPPORTFILES = $(TIMEDIFF) first.c test.h -+FIRSTFILES = first.c first.h -+SUPPORTFILES = $(TIMEDIFF) $(FIRSTFILES) test.h -+ -+THREADS = ../../lib/curl_threads.c ../../lib/curl_threads.h - - # These are all libcurl test programs --noinst_PROGRAMS = chkhostname libauthretry libntlmconnect libprereq \ -+LIBTESTPROGS = libauthretry libntlmconnect libprereq \ - lib500 lib501 lib502 lib503 lib504 lib505 lib506 lib507 lib508 lib509 \ - lib510 lib511 lib512 lib513 lib514 lib515 lib516 lib517 lib518 lib519 \ - lib520 lib521 lib523 lib524 lib525 lib526 lib527 lib529 lib530 lib532 \ -@@ -54,6 +57,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect libprereq \ - lib670 lib671 lib672 lib673 lib674 lib676 lib677 lib678 \ - lib1156 \ - lib1301 \ -+ lib1485 \ - lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \ - lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 lib1517 \ - lib1518 lib1520 lib1521 lib1522 lib1523 \ -@@ -66,27 +70,24 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect libprereq \ - \ - lib1662 \ - \ -- lib1900 \ -+ lib1900 lib1901 \ - lib1903 lib1905 lib1906 lib1907 lib1908 lib1910 lib1911 lib1912 lib1913 \ - lib1915 lib1916 lib1917 lib1918 lib1919 \ - lib1933 lib1934 lib1935 lib1936 lib1937 lib1938 lib1939 lib1940 \ - lib1945 lib1946 lib1947 lib1948 lib1955 lib1956 lib1957 lib1958 lib1959 \ - lib1960 lib1964 \ - lib1970 lib1971 lib1972 lib1973 lib1974 lib1975 \ -- lib2301 lib2302 lib2304 lib2305 lib2306 \ -- lib2402 lib2404 \ -+ lib2301 lib2302 lib2304 lib2305 lib2306 lib2308 \ -+ lib2402 lib2404 lib2405 \ - lib2502 \ - lib3010 lib3025 lib3026 lib3027 \ -- lib3100 lib3101 lib3102 lib3103 -- --chkhostname_SOURCES = chkhostname.c ../../lib/curl_gethostname.c --chkhostname_LDADD = @CURL_NETWORK_LIBS@ --chkhostname_DEPENDENCIES = -+ lib3100 lib3101 lib3102 lib3103 lib3207 - - libntlmconnect_SOURCES = libntlmconnect.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - libntlmconnect_LDADD = $(TESTUTIL_LIBS) - - libauthretry_SOURCES = libauthretry.c $(SUPPORTFILES) -+libauthretry_LDADD = $(TESTUTIL_LIBS) - - libprereq_SOURCES = libprereq.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - libprereq_LDADD = $(TESTUTIL_LIBS) -@@ -346,6 +347,9 @@ lib678_LDADD = $(TESTUTIL_LIBS) - lib1301_SOURCES = lib1301.c $(SUPPORTFILES) $(TESTUTIL) - lib1301_LDADD = $(TESTUTIL_LIBS) - -+lib1485_SOURCES = lib1485.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib1485_LDADD = $(TESTUTIL_LIBS) -+ - lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL) - lib1500_LDADD = $(TESTUTIL_LIBS) - -@@ -398,7 +402,7 @@ lib1513_LDADD = $(TESTUTIL_LIBS) - lib1514_SOURCES = lib1514.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib1514_LDADD = $(TESTUTIL_LIBS) - --lib1515_SOURCES = lib1515.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib1515_SOURCES = lib1515.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(WARNLESS) - lib1515_LDADD = $(TESTUTIL_LIBS) - - lib1517_SOURCES = lib1517.c $(SUPPORTFILES) -@@ -461,7 +465,7 @@ lib1539_SOURCES = lib1514.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib1539_LDADD = $(TESTUTIL_LIBS) - lib1539_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1539 - --lib1540_SOURCES = lib1540.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib1540_SOURCES = lib1540.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(WARNLESS) - lib1540_LDADD = $(TESTUTIL_LIBS) - - lib1541_SOURCES = lib1541.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -@@ -474,7 +478,6 @@ lib1543_SOURCES = lib1518.c $(SUPPORTFILES) - lib1543_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1543 - - lib1545_SOURCES = lib1545.c $(SUPPORTFILES) --lib1545_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_DISABLE_DEPRECATION - - lib1550_SOURCES = lib1550.c $(SUPPORTFILES) - -@@ -483,7 +486,7 @@ lib1551_SOURCES = lib1551.c $(SUPPORTFILES) - lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL) - lib1552_LDADD = $(TESTUTIL_LIBS) - --lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TESTUTIL) -+lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TSTTRACE) $(TESTUTIL) - lib1553_LDADD = $(TESTUTIL_LIBS) - - lib1554_SOURCES = lib1554.c $(SUPPORTFILES) -@@ -545,6 +548,8 @@ lib1662_LDADD = $(TESTUTIL_LIBS) - - lib1900_SOURCES = lib1900.c $(SUPPORTFILES) - -+lib1901_SOURCES = lib1901.c $(SUPPORTFILES) -+ - lib1903_SOURCES = lib1903.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib1903_LDADD = $(TESTUTIL_LIBS) - -@@ -572,7 +577,7 @@ lib1912_LDADD = $(TESTUTIL_LIBS) - lib1913_SOURCES = lib1913.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib1913_LDADD = $(TESTUTIL_LIBS) - --lib1915_SOURCES = lib1915.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib1915_SOURCES = lib1915.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(WARNLESS) - lib1915_LDADD = $(TESTUTIL_LIBS) - - lib1916_SOURCES = lib1916.c $(SUPPORTFILES) $(WARNLESS) -@@ -675,13 +680,19 @@ lib2305_LDADD = $(TESTUTIL_LIBS) - lib2306_SOURCES = lib2306.c $(SUPPORTFILES) - lib2306_LDADD = $(TESTUTIL_LIBS) - -+lib2308_SOURCES = lib2308.c $(SUPPORTFILES) -+lib2308_LDADD = $(TESTUTIL_LIBS) -+ - lib2402_SOURCES = lib2402.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib2402_LDADD = $(TESTUTIL_LIBS) - - lib2404_SOURCES = lib2404.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) - lib2404_LDADD = $(TESTUTIL_LIBS) - --lib2502_SOURCES = lib2502.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib2405_SOURCES = lib2405.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -+lib2405_LDADD = $(TESTUTIL_LIBS) -+ -+lib2502_SOURCES = lib2502.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(WARNLESS) - lib2502_LDADD = $(TESTUTIL_LIBS) - - lib3010_SOURCES = lib3010.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -@@ -707,3 +718,6 @@ lib3102_LDADD = $(TESTUTIL_LIBS) - - lib3103_SOURCES = lib3103.c $(SUPPORTFILES) - lib3103_LDADD = $(TESTUTIL_LIBS) -+ -+lib3207_SOURCES = lib3207.c $(SUPPORTFILES) $(TESTUTIL) $(THREADS) $(WARNLESS) $(MULTIBYTE) -+lib3207_LDADD = $(TESTUTIL_LIBS) -diff --git a/tests/libtest/first.c b/tests/libtest/first.c -index 42c53c694..68c649e08 100644 ---- a/tests/libtest/first.c -+++ b/tests/libtest/first.c -@@ -22,6 +22,7 @@ - * - ***************************************************************************/ - #include "test.h" -+#include "first.h" - - #ifdef HAVE_LOCALE_H - # include /* for setlocale() */ -@@ -120,15 +121,15 @@ static void memory_tracking_init(void) - #endif - - /* returns a hexdump in a static memory area */ --char *hexdump(const unsigned char *buffer, size_t len) -+char *hexdump(const unsigned char *buf, size_t len) - { - static char dump[200 * 3 + 1]; - char *p = dump; - size_t i; - if(len > 200) - return NULL; -- for(i = 0; i2) -- libtest_arg2 = argv[2]; -+ if(argc > (basearg + 1)) -+ libtest_arg2 = argv[basearg + 1]; - -- if(argc>3) -- libtest_arg3 = argv[3]; -+ if(argc > (basearg + 2)) -+ libtest_arg3 = argv[basearg + 2]; - -- URL = argv[1]; /* provide this to the rest */ -+ URL = argv[basearg]; /* provide this to the rest */ - - fprintf(stderr, "URL: %s\n", URL); - -- result = test(URL); -+ result = test_func(URL); - fprintf(stderr, "Test ended with result %d\n", result); - - #ifdef _WIN32 -@@ -185,5 +227,5 @@ int main(int argc, char **argv) - - /* Regular program status codes are limited to 0..127 and 126 and 127 have - * special meanings by the shell, so limit a normal return code to 125 */ -- return result <= 125 ? result : 125; -+ return (int)result <= 125 ? (int)result : 125; - } -diff --git a/tests/libtest/first.h b/tests/libtest/first.h -new file mode 100644 -index 000000000..1e4ae5fc3 ---- /dev/null -+++ b/tests/libtest/first.h -@@ -0,0 +1,38 @@ -+#ifndef HEADER_LIBTEST_FIRST_H -+#define HEADER_LIBTEST_FIRST_H -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+#include "curl_setup.h" -+#include -+ -+typedef CURLcode (*test_func_t)(char *); -+ -+#ifdef CURLTESTS_BUNDLED -+struct onetest { -+ const char *name; -+ test_func_t ptr; -+}; -+#endif -+ -+#endif /* HEADER_LIBTEST_FIRST_H */ -diff --git a/tests/libtest/lib1156.c b/tests/libtest/lib1156.c -index b512ef67a..6854e3bc4 100644 ---- a/tests/libtest/lib1156.c -+++ b/tests/libtest/lib1156.c -@@ -47,7 +47,7 @@ struct testparams { - CURLcode result; /* Code that should be returned by curl_easy_perform(). */ - }; - --static const struct testparams params[] = { -+static const struct testparams testparams[] = { - { 0, CURLE_OK }, - { F_CONTENTRANGE, CURLE_OK }, - { F_FAIL, CURLE_OK }, -@@ -90,35 +90,35 @@ static int onetest(CURL *curl, const char *url, const struct testparams *p, - unsigned int replyselector; - char urlbuf[256]; - -- replyselector = (p->flags & F_CONTENTRANGE)? 1: 0; -+ replyselector = (p->flags & F_CONTENTRANGE) ? 1 : 0; - if(p->flags & F_HTTP416) - replyselector += 2; - msnprintf(urlbuf, sizeof(urlbuf), "%s%04u", url, replyselector); - test_setopt(curl, CURLOPT_URL, urlbuf); - test_setopt(curl, CURLOPT_VERBOSE, 1L); -- test_setopt(curl, CURLOPT_RESUME_FROM, (p->flags & F_RESUME)? 3: 0); -- test_setopt(curl, CURLOPT_RANGE, !(p->flags & F_RESUME)? -+ test_setopt(curl, CURLOPT_RESUME_FROM, (p->flags & F_RESUME) ? 3 : 0); -+ test_setopt(curl, CURLOPT_RANGE, !(p->flags & F_RESUME) ? - "3-1000000": (char *) NULL); -- test_setopt(curl, CURLOPT_FAILONERROR, (p->flags & F_FAIL)? 1: 0); -+ test_setopt(curl, CURLOPT_FAILONERROR, (p->flags & F_FAIL) ? 1 : 0); - hasbody = 0; - res = curl_easy_perform(curl); - if(res != p->result) { - printf("%zd: bad error code (%d): resume=%s, fail=%s, http416=%s, " - "content-range=%s, expected=%d\n", num, res, -- (p->flags & F_RESUME)? "yes": "no", -- (p->flags & F_FAIL)? "yes": "no", -- (p->flags & F_HTTP416)? "yes": "no", -- (p->flags & F_CONTENTRANGE)? "yes": "no", -+ (p->flags & F_RESUME) ? "yes": "no", -+ (p->flags & F_FAIL) ? "yes": "no", -+ (p->flags & F_HTTP416) ? "yes": "no", -+ (p->flags & F_CONTENTRANGE) ? "yes": "no", - p->result); - return 1; - } - if(hasbody && (p->flags & F_IGNOREBODY)) { - printf("body should be ignored and is not: resume=%s, fail=%s, " - "http416=%s, content-range=%s\n", -- (p->flags & F_RESUME)? "yes": "no", -- (p->flags & F_FAIL)? "yes": "no", -- (p->flags & F_HTTP416)? "yes": "no", -- (p->flags & F_CONTENTRANGE)? "yes": "no"); -+ (p->flags & F_RESUME) ? "yes": "no", -+ (p->flags & F_FAIL) ? "yes": "no", -+ (p->flags & F_HTTP416) ? "yes": "no", -+ (p->flags & F_CONTENTRANGE) ? "yes": "no"); - return 1; - } - return 0; -@@ -131,7 +131,7 @@ test_cleanup: - /* for debugging: */ - /* #define SINGLETEST 9 */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -143,7 +143,7 @@ int test(char *URL) - return TEST_ERR_MAJOR_BAD; - } - -- for(i = 0; i < sizeof(params) / sizeof(params[0]); i++) { -+ for(i = 0; i < sizeof(testparams) / sizeof(testparams[0]); i++) { - curl = curl_easy_init(); - if(!curl) { - fprintf(stderr, "curl_easy_init() failed\n"); -@@ -156,18 +156,18 @@ int test(char *URL) - #ifdef SINGLETEST - if(SINGLETEST == i) - #endif -- status |= onetest(curl, URL, params + i, i); -+ status |= onetest(curl, URL, testparams + i, i); - curl_easy_cleanup(curl); - } - - curl_global_cleanup(); - printf("%d\n", status); -- return status; -+ return (CURLcode)status; - - test_cleanup: - - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1301.c b/tests/libtest/lib1301.c -index f63b94ccd..de3aaeac6 100644 ---- a/tests/libtest/lib1301.c -+++ b/tests/libtest/lib1301.c -@@ -28,11 +28,11 @@ - if(!(expr)) { \ - fprintf(stderr, "%s:%d Assertion '%s' failed: %s\n", \ - __FILE__, __LINE__, #expr, msg); \ -- return 1; \ -+ return (CURLcode)1; \ - } \ - } while(0) - --int test(char *URL) -+CURLcode test(char *URL) - { - int rc; - (void)URL; -@@ -58,5 +58,5 @@ int test(char *URL) - rc = curl_strnequal("ii", "II", 3); - fail_unless(rc != 0, "return code should be non-zero"); - -- return 0; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib1485.c b/tests/libtest/lib1485.c -new file mode 100644 -index 000000000..650746a37 ---- /dev/null -+++ b/tests/libtest/lib1485.c -@@ -0,0 +1,120 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+#include "test.h" -+ -+#include "testutil.h" -+#include "warnless.h" -+#include "memdebug.h" -+ -+struct transfer_status { -+ CURL *easy; -+ curl_off_t out_len; -+ size_t hd_line; -+ CURLcode result; -+ int http_status; -+}; -+ -+static size_t header_callback(char *ptr, size_t size, size_t nmemb, -+ void *userp) -+{ -+ struct transfer_status *st = (struct transfer_status *)userp; -+ const char *hd = ptr; -+ size_t len = size * nmemb; -+ CURLcode result; -+ -+ (void)fwrite(ptr, size, nmemb, stdout); -+ ++st->hd_line; -+ if(len == 2 && hd[0] == '\r' && hd[1] == '\n') { -+ curl_off_t clen; -+ long httpcode = 0; -+ /* end of a response */ -+ result = curl_easy_getinfo(st->easy, CURLINFO_RESPONSE_CODE, &httpcode); -+ fprintf(stderr, "header_callback, get status: %ld, %d\n", -+ httpcode, result); -+ if(httpcode < 100 || httpcode >= 1000) { -+ fprintf(stderr, "header_callback, invalid status: %ld, %d\n", -+ httpcode, result); -+ return CURLE_WRITE_ERROR; -+ } -+ st->http_status = (int)httpcode; -+ if(st->http_status >= 200 && st->http_status < 300) { -+ result = curl_easy_getinfo(st->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, -+ &clen); -+ fprintf(stderr, "header_callback, info Content-Length: %ld, %d\n", -+ (long)clen, result); -+ if(result) { -+ st->result = result; -+ return CURLE_WRITE_ERROR; -+ } -+ if(clen < 0) { -+ fprintf(stderr, "header_callback, expected known Content-Length, " -+ "got: %ld\n", (long)clen); -+ return CURLE_WRITE_ERROR; -+ } -+ } -+ } -+ return len; -+} -+ -+static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp) -+{ -+ struct transfer_status *st = (struct transfer_status *)userp; -+ size_t len = size * nmemb; -+ fwrite(ptr, size, nmemb, stdout); -+ st->out_len += (curl_off_t)len; -+ return len; -+} -+ -+CURLcode test(char *URL) -+{ -+ CURL *curls = NULL; -+ CURLcode res = CURLE_OK; -+ struct transfer_status st; -+ -+ start_test_timing(); -+ -+ memset(&st, 0, sizeof(st)); -+ -+ global_init(CURL_GLOBAL_ALL); -+ -+ easy_init(curls); -+ st.easy = curls; /* to allow callbacks access */ -+ -+ easy_setopt(curls, CURLOPT_URL, URL); -+ easy_setopt(curls, CURLOPT_WRITEFUNCTION, write_callback); -+ easy_setopt(curls, CURLOPT_WRITEDATA, &st); -+ easy_setopt(curls, CURLOPT_HEADERFUNCTION, header_callback); -+ easy_setopt(curls, CURLOPT_HEADERDATA, &st); -+ -+ easy_setopt(curls, CURLOPT_NOPROGRESS, 1L); -+ -+ res = curl_easy_perform(curls); -+ -+test_cleanup: -+ -+ curl_easy_cleanup(curls); -+ curl_global_cleanup(); -+ -+ return res; /* return the final return code */ -+} -diff --git a/tests/libtest/lib1500.c b/tests/libtest/lib1500.c -index 3f237a031..9f4ff07ea 100644 ---- a/tests/libtest/lib1500.c -+++ b/tests/libtest/lib1500.c -@@ -29,13 +29,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; - CURLM *multi = NULL; - int still_running; -- int i = TEST_ERR_FAILURE; -- int res = 0; -+ CURLcode i = TEST_ERR_FAILURE; -+ CURLcode res = CURLE_OK; - CURLMsg *msg; - - start_test_timing(); -@@ -56,10 +56,11 @@ int test(char *URL) - abort_on_test_timeout(); - - while(still_running) { -+ CURLMcode mres; - int num; -- res = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -- if(res != CURLM_OK) { -- printf("curl_multi_wait() returned %d\n", res); -+ mres = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -+ if(mres != CURLM_OK) { -+ printf("curl_multi_wait() returned %d\n", mres); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -diff --git a/tests/libtest/lib1501.c b/tests/libtest/lib1501.c -index a4816c777..ced1d5d98 100644 ---- a/tests/libtest/lib1501.c -+++ b/tests/libtest/lib1501.c -@@ -35,11 +35,11 @@ - to allow old and slow machines to run this test too */ - #define MAX_BLOCKED_TIME_MS 500 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURLM *mhandle = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int still_running = 0; - - start_test_timing(); -@@ -96,7 +96,7 @@ int test(char *URL) - fprintf(stderr, "pong = %ld\n", e); - - if(e > MAX_BLOCKED_TIME_MS) { -- res = 100; -+ res = (CURLcode) 100; - break; - } - } -diff --git a/tests/libtest/lib1502.c b/tests/libtest/lib1502.c -index 2e2415b72..d4ebdf501 100644 ---- a/tests/libtest/lib1502.c -+++ b/tests/libtest/lib1502.c -@@ -39,13 +39,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - CURL *dup; - CURLM *multi = NULL; - int still_running; -- int res = 0; -+ CURLcode res = CURLE_OK; - - char redirect[160]; - -diff --git a/tests/libtest/lib1506.c b/tests/libtest/lib1506.c -index a1a72b2a1..2dbda6d0d 100644 ---- a/tests/libtest/lib1506.c -+++ b/tests/libtest/lib1506.c -@@ -31,9 +31,9 @@ - - #define NUM_HANDLES 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES] = {0}; - int running; - CURLM *m = NULL; -diff --git a/tests/libtest/lib1507.c b/tests/libtest/lib1507.c -index d23e0b184..fc788459c 100644 ---- a/tests/libtest/lib1507.c -+++ b/tests/libtest/lib1507.c -@@ -47,9 +47,9 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return CURL_READFUNC_ABORT; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - CURLM *mcurl = NULL; - int still_running = 1; -diff --git a/tests/libtest/lib1508.c b/tests/libtest/lib1508.c -index 981039137..bece5fc92 100644 ---- a/tests/libtest/lib1508.c -+++ b/tests/libtest/lib1508.c -@@ -27,9 +27,9 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURLM *m = NULL; - - (void)URL; -diff --git a/tests/libtest/lib1509.c b/tests/libtest/lib1509.c -index 2277e6cee..328ebd5d0 100644 ---- a/tests/libtest/lib1509.c -+++ b/tests/libtest/lib1509.c -@@ -27,17 +27,17 @@ - #include "warnless.h" - #include "memdebug.h" - --size_t WriteOutput(void *ptr, size_t size, size_t nmemb, void *stream); --size_t WriteHeader(void *ptr, size_t size, size_t nmemb, void *stream); -+size_t WriteOutput(char *ptr, size_t size, size_t nmemb, void *stream); -+size_t WriteHeader(char *ptr, size_t size, size_t nmemb, void *stream); - - static unsigned long realHeaderSize = 0; - --int test(char *URL) -+CURLcode test(char *URL) - { - long headerSize; - CURLcode code; - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -@@ -57,7 +57,7 @@ int test(char *URL) - if(CURLE_OK != code) { - fprintf(stderr, "%s:%d curl_easy_perform() failed, " - "with code %d (%s)\n", -- __FILE__, __LINE__, (int)code, curl_easy_strerror(code)); -+ __FILE__, __LINE__, code, curl_easy_strerror(code)); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -@@ -66,7 +66,7 @@ int test(char *URL) - if(CURLE_OK != code) { - fprintf(stderr, "%s:%d curl_easy_getinfo() failed, " - "with code %d (%s)\n", -- __FILE__, __LINE__, (int)code, curl_easy_strerror(code)); -+ __FILE__, __LINE__, code, curl_easy_strerror(code)); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -@@ -82,13 +82,13 @@ test_cleanup: - return res; - } - --size_t WriteOutput(void *ptr, size_t size, size_t nmemb, void *stream) -+size_t WriteOutput(char *ptr, size_t size, size_t nmemb, void *stream) - { - fwrite(ptr, size, nmemb, stream); - return nmemb * size; - } - --size_t WriteHeader(void *ptr, size_t size, size_t nmemb, void *stream) -+size_t WriteHeader(char *ptr, size_t size, size_t nmemb, void *stream) - { - (void)ptr; - (void)stream; -diff --git a/tests/libtest/lib1510.c b/tests/libtest/lib1510.c -index 927927e49..b3764b8b6 100644 ---- a/tests/libtest/lib1510.c -+++ b/tests/libtest/lib1510.c -@@ -31,9 +31,9 @@ - - #define NUM_URLS 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - int i; - char target_url[256]; -diff --git a/tests/libtest/lib1511.c b/tests/libtest/lib1511.c -index d093a5bd2..abc1356e5 100644 ---- a/tests/libtest/lib1511.c -+++ b/tests/libtest/lib1511.c -@@ -25,11 +25,11 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - long unmet; - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1512.c b/tests/libtest/lib1512.c -index 670781982..a93bfc029 100644 ---- a/tests/libtest/lib1512.c -+++ b/tests/libtest/lib1512.c -@@ -34,9 +34,9 @@ - - #define NUM_HANDLES 2 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES] = {NULL, NULL}; - char *port = libtest_arg3; - char *address = libtest_arg2; -diff --git a/tests/libtest/lib1513.c b/tests/libtest/lib1513.c -index 19c23c06e..392e6c612 100644 ---- a/tests/libtest/lib1513.c -+++ b/tests/libtest/lib1513.c -@@ -47,10 +47,10 @@ static int progressKiller(void *arg, - return 1; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1514.c b/tests/libtest/lib1514.c -index 6582b5977..6b4e18bac 100644 ---- a/tests/libtest/lib1514.c -+++ b/tests/libtest/lib1514.c -@@ -30,7 +30,7 @@ - - #include "memdebug.h" - --static char data[]="dummy"; -+static char testdata[]="dummy"; - - struct WriteThis { - char *readptr; -@@ -54,12 +54,12 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode result = CURLE_OK; -- int res = 0; -- struct WriteThis pooh = { data, sizeof(data)-1 }; -+ CURLcode res = CURLE_OK; -+ struct WriteThis pooh = { testdata, sizeof(testdata)-1 }; - - global_init(CURL_GLOBAL_ALL); - -@@ -82,5 +82,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)result; -+ return result; - } -diff --git a/tests/libtest/lib1515.c b/tests/libtest/lib1515.c -index d210ed3be..f772d9e38 100644 ---- a/tests/libtest/lib1515.c -+++ b/tests/libtest/lib1515.c -@@ -29,6 +29,7 @@ - */ - - #include "test.h" -+#include "testtrace.h" - #include "testutil.h" - #include "warnless.h" - #include "memdebug.h" -@@ -37,24 +38,12 @@ - - #define DNS_TIMEOUT 1 - --static int debug_callback(CURL *curl, curl_infotype info, char *msg, -- size_t len, void *ptr) --{ -- (void)curl; -- (void)ptr; -- -- if(info == CURLINFO_TEXT) -- fprintf(stderr, "debug: %.*s", (int) len, msg); -- -- return 0; --} -- --static int do_one_request(CURLM *m, char *URL, char *resolve) -+static CURLcode do_one_request(CURLM *m, char *URL, char *resolve) - { - CURL *curls; - struct curl_slist *resolve_list = NULL; - int still_running; -- int res = 0; -+ CURLcode res = CURLE_OK; - CURLMsg *msg; - int msgs_left; - -@@ -64,10 +53,14 @@ static int do_one_request(CURLM *m, char *URL, char *resolve) - - easy_setopt(curls, CURLOPT_URL, URL); - easy_setopt(curls, CURLOPT_RESOLVE, resolve_list); -- easy_setopt(curls, CURLOPT_DEBUGFUNCTION, debug_callback); -- easy_setopt(curls, CURLOPT_VERBOSE, 1); - easy_setopt(curls, CURLOPT_DNS_CACHE_TIMEOUT, DNS_TIMEOUT); - -+ libtest_debug_config.nohex = 1; -+ libtest_debug_config.tracetime = 1; -+ easy_setopt(curls, CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(curls, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); -+ easy_setopt(curls, CURLOPT_VERBOSE, 1L); -+ - multi_add_handle(m, curls); - multi_perform(m, &still_running); - -@@ -110,10 +103,10 @@ test_cleanup: - return res; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *multi = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - char *address = libtest_arg2; - char *port = libtest_arg3; - char *path = URL; -@@ -127,6 +120,7 @@ int test(char *URL) - start_test_timing(); - - global_init(CURL_GLOBAL_ALL); -+ curl_global_trace("all"); - multi_init(multi); - - for(i = 1; i <= count; i++) { -@@ -136,8 +130,10 @@ int test(char *URL) - - /* second request must succeed like the first one */ - res = do_one_request(multi, target_url, dns_entry); -- if(res) -+ if(res != CURLE_OK) { -+ fprintf(stderr, "request %s failed with %d\n", target_url, res); - goto test_cleanup; -+ } - - if(i < count) - sleep(DNS_TIMEOUT + 1); -@@ -148,5 +144,5 @@ test_cleanup: - curl_multi_cleanup(multi); - curl_global_cleanup(); - -- return (int) res; -+ return res; - } -diff --git a/tests/libtest/lib1517.c b/tests/libtest/lib1517.c -index 126792017..3957eb199 100644 ---- a/tests/libtest/lib1517.c -+++ b/tests/libtest/lib1517.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]="this is what we post to the silly web server\n"; -+static char testdata[]="this is what we post to the silly web server\n"; - - struct WriteThis { - char *readptr; -@@ -53,7 +53,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return tocopy; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -64,14 +64,14 @@ int test(char *URL) - #if (defined(_WIN32) || defined(__CYGWIN__)) - printf("Windows TCP does not deliver response data but reports " - "CONNABORTED\n"); -- return 1; /* skip since test will fail on Windows without workaround */ -+ return (CURLcode)1; /* skip since it fails on Windows without workaround */ - #else -- return 0; /* sure, run this! */ -+ return CURLE_OK; /* sure, run this! */ - #endif - } - -- pooh.readptr = data; -- pooh.sizeleft = strlen(data); -+ pooh.readptr = testdata; -+ pooh.sizeleft = strlen(testdata); - - if(curl_global_init(CURL_GLOBAL_ALL)) { - fprintf(stderr, "curl_global_init() failed\n"); -diff --git a/tests/libtest/lib1518.c b/tests/libtest/lib1518.c -index aa0de4155..560d79ce2 100644 ---- a/tests/libtest/lib1518.c -+++ b/tests/libtest/lib1518.c -@@ -37,7 +37,7 @@ static size_t writecb(char *buffer, size_t size, size_t nitems, - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -84,13 +84,13 @@ int test(char *URL) - test_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); - - printf("res %d\n" -- "status %d\n" -- "redirects %d\n" -+ "status %ld\n" -+ "redirects %ld\n" - "effectiveurl %s\n" - "redirecturl %s\n", -- (int)res, -- (int)curlResponseCode, -- (int)curlRedirectCount, -+ res, -+ curlResponseCode, -+ curlRedirectCount, - effectiveUrl, - redirectUrl ? redirectUrl : "blank"); - -diff --git a/tests/libtest/lib1520.c b/tests/libtest/lib1520.c -index 5b6c3dcfb..8e5f6a9be 100644 ---- a/tests/libtest/lib1520.c -+++ b/tests/libtest/lib1520.c -@@ -71,7 +71,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -111,5 +111,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1522.c b/tests/libtest/lib1522.c -index f5e87e014..3d171009b 100644 ---- a/tests/libtest/lib1522.c -+++ b/tests/libtest/lib1522.c -@@ -49,7 +49,7 @@ static int sockopt_callback(void *clientp, curl_socket_t curlfd, - return CURL_SOCKOPT_OK; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode code = TEST_ERR_MAJOR_BAD; - CURLcode res; -@@ -97,5 +97,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)code; -+ return code; - } -diff --git a/tests/libtest/lib1523.c b/tests/libtest/lib1523.c -index 9aa9e3cb4..529bbf83d 100644 ---- a/tests/libtest/lib1523.c -+++ b/tests/libtest/lib1523.c -@@ -55,7 +55,7 @@ static CURLcode run(CURL *hnd, long limit, long time) - return curl_easy_perform(hnd); - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret; - CURL *hnd; -@@ -81,5 +81,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - curl_global_cleanup(); - -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib1525.c b/tests/libtest/lib1525.c -index 591eb413f..c8a3063f3 100644 ---- a/tests/libtest/lib1525.c -+++ b/tests/libtest/lib1525.c -@@ -32,21 +32,21 @@ - - #include "memdebug.h" - --static char data [] = "Hello Cloud!\n"; -+static char testdata[] = "Hello Cloud!\n"; - - static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) - { - size_t amount = nmemb * size; /* Total bytes curl wants */ -- if(amount < strlen(data)) { -- return strlen(data); -+ if(amount < strlen(testdata)) { -+ return strlen(testdata); - } - (void)stream; -- memcpy(ptr, data, strlen(data)); -- return strlen(data); -+ memcpy(ptr, testdata, strlen(testdata)); -+ return strlen(testdata); - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -84,7 +84,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); - test_setopt(curl, CURLOPT_READFUNCTION, read_callback); - test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); -- test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(data)); -+ test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(testdata)); - - res = curl_easy_perform(curl); - -@@ -96,5 +96,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1526.c b/tests/libtest/lib1526.c -index c11e536eb..8093079f5 100644 ---- a/tests/libtest/lib1526.c -+++ b/tests/libtest/lib1526.c -@@ -31,20 +31,20 @@ - - #include "memdebug.h" - --static char data [] = "Hello Cloud!\n"; -+static char testdata[] = "Hello Cloud!\n"; - - static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) - { - size_t amount = nmemb * size; /* Total bytes curl wants */ -- if(amount < strlen(data)) { -- return strlen(data); -+ if(amount < strlen(testdata)) { -+ return strlen(testdata); - } - (void)stream; -- memcpy(ptr, data, strlen(data)); -- return strlen(data); -+ memcpy(ptr, testdata, strlen(testdata)); -+ return strlen(testdata); - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -87,7 +87,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); - test_setopt(curl, CURLOPT_READFUNCTION, read_callback); - test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); -- test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(data)); -+ test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(testdata)); - - res = curl_easy_perform(curl); - -@@ -101,5 +101,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1527.c b/tests/libtest/lib1527.c -index e59870585..26581b2a3 100644 ---- a/tests/libtest/lib1527.c -+++ b/tests/libtest/lib1527.c -@@ -31,21 +31,21 @@ - - #include "memdebug.h" - --static char data [] = "Hello Cloud!\n"; -+static char testdata[] = "Hello Cloud!\n"; - - static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) - { - size_t amount = nmemb * size; /* Total bytes curl wants */ -- if(amount < strlen(data)) { -- return strlen(data); -+ if(amount < strlen(testdata)) { -+ return strlen(testdata); - } - (void)stream; -- memcpy(ptr, data, strlen(data)); -- return strlen(data); -+ memcpy(ptr, testdata, strlen(testdata)); -+ return strlen(testdata); - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -85,7 +85,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); - test_setopt(curl, CURLOPT_READFUNCTION, read_callback); - test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); -- test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(data)); -+ test_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(testdata)); - test_setopt(curl, CURLOPT_HEADEROPT, CURLHEADER_UNIFIED); - - res = curl_easy_perform(curl); -@@ -98,5 +98,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1528.c b/tests/libtest/lib1528.c -index ae2360414..396910a5e 100644 ---- a/tests/libtest/lib1528.c -+++ b/tests/libtest/lib1528.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -71,5 +71,5 @@ test_cleanup: - curl_slist_free_all(phl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1529.c b/tests/libtest/lib1529.c -index 5b0f990fd..8a1f52cd3 100644 ---- a/tests/libtest/lib1529.c -+++ b/tests/libtest/lib1529.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -59,5 +59,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1530.c b/tests/libtest/lib1530.c -index e45949294..6b86cdb6f 100644 ---- a/tests/libtest/lib1530.c -+++ b/tests/libtest/lib1530.c -@@ -37,7 +37,7 @@ static curl_socket_t opensocket(void *clientp, - return CURL_SOCKET_BAD; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -66,5 +66,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1531.c b/tests/libtest/lib1531.c -index b64e16603..f4814f122 100644 ---- a/tests/libtest/lib1531.c -+++ b/tests/libtest/lib1531.c -@@ -33,14 +33,14 @@ - static char const testData[] = ".abc\0xyz"; - static off_t const testDataSize = sizeof(testData) - 1; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy; - CURLM *multi_handle; - int still_running; /* keep number of running handles */ - CURLMsg *msg; /* for picking up messages with the transfer status */ - int msgs_left; /* how many messages are left */ -- int res = CURLE_OK; -+ CURLcode res = CURLE_OK; - - start_test_timing(); - -diff --git a/tests/libtest/lib1532.c b/tests/libtest/lib1532.c -index a3ac70929..22b1aadaa 100644 ---- a/tests/libtest/lib1532.c -+++ b/tests/libtest/lib1532.c -@@ -27,7 +27,7 @@ - - /* Test CURLINFO_RESPONSE_CODE */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - long httpcode; -@@ -78,5 +78,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1533.c b/tests/libtest/lib1533.c -index 0c9f8fa95..e1dd16c9c 100644 ---- a/tests/libtest/lib1533.c -+++ b/tests/libtest/lib1533.c -@@ -106,7 +106,7 @@ static int perform_and_check_connections(CURL *curl, const char *description, - - res = curl_easy_perform(curl); - if(res != CURLE_OK) { -- fprintf(stderr, "curl_easy_perform() failed with %d\n", (int)res); -+ fprintf(stderr, "curl_easy_perform() failed with %d\n", res); - return TEST_ERR_MAJOR_BAD; - } - -@@ -127,11 +127,12 @@ static int perform_and_check_connections(CURL *curl, const char *description, - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - struct cb_data data; - CURL *curl = NULL; -- int res = TEST_ERR_FAILURE; -+ CURLcode res = TEST_ERR_FAILURE; -+ int result; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); -@@ -157,17 +158,19 @@ int test(char *URL) - test_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - test_setopt(curl, CURLOPT_WRITEDATA, &data); - -- res = perform_and_check_connections(curl, -+ result = perform_and_check_connections(curl, - "First request without CURLOPT_KEEP_SENDING_ON_ERROR", 1); -- if(res != TEST_ERR_SUCCESS) { -+ if(result != TEST_ERR_SUCCESS) { -+ res = (CURLcode) result; - goto test_cleanup; - } - - reset_data(&data, curl); - -- res = perform_and_check_connections(curl, -+ result = perform_and_check_connections(curl, - "Second request without CURLOPT_KEEP_SENDING_ON_ERROR", 1); -- if(res != TEST_ERR_SUCCESS) { -+ if(result != TEST_ERR_SUCCESS) { -+ res = (CURLcode) result; - goto test_cleanup; - } - -@@ -175,17 +178,19 @@ int test(char *URL) - - reset_data(&data, curl); - -- res = perform_and_check_connections(curl, -+ result = perform_and_check_connections(curl, - "First request with CURLOPT_KEEP_SENDING_ON_ERROR", 1); -- if(res != TEST_ERR_SUCCESS) { -+ if(result != TEST_ERR_SUCCESS) { -+ res = (CURLcode) result; - goto test_cleanup; - } - - reset_data(&data, curl); - -- res = perform_and_check_connections(curl, -+ result = perform_and_check_connections(curl, - "Second request with CURLOPT_KEEP_SENDING_ON_ERROR", 0); -- if(res != TEST_ERR_SUCCESS) { -+ if(result != TEST_ERR_SUCCESS) { -+ res = (CURLcode) result; - goto test_cleanup; - } - -@@ -197,5 +202,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1534.c b/tests/libtest/lib1534.c -index 620e38338..a9a7d73d8 100644 ---- a/tests/libtest/lib1534.c -+++ b/tests/libtest/lib1534.c -@@ -27,7 +27,7 @@ - - /* Test CURLINFO_FILETIME */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl, *dupe = NULL; - long filetime; -@@ -127,5 +127,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_easy_cleanup(dupe); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1535.c b/tests/libtest/lib1535.c -index 6edf88731..80589d893 100644 ---- a/tests/libtest/lib1535.c -+++ b/tests/libtest/lib1535.c -@@ -27,7 +27,7 @@ - - /* Test CURLINFO_PROTOCOL */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl, *dupe = NULL; - long protocol; -@@ -134,5 +134,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_easy_cleanup(dupe); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1536.c b/tests/libtest/lib1536.c -index 9ba7ec18e..7bc9e718b 100644 ---- a/tests/libtest/lib1536.c -+++ b/tests/libtest/lib1536.c -@@ -27,7 +27,7 @@ - - /* Test CURLINFO_SCHEME */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl, *dupe = NULL; - char *scheme; -@@ -71,9 +71,9 @@ int test(char *URL) - __FILE__, __LINE__, res, curl_easy_strerror(res)); - goto test_cleanup; - } -- if(!scheme || memcmp(scheme, "HTTP", 5) != 0) { -+ if(!scheme || memcmp(scheme, "http", 5) != 0) { - fprintf(stderr, "%s:%d scheme of http resource is incorrect; " -- "expected 'HTTP' but is %s\n", -+ "expected 'http' but is %s\n", - __FILE__, __LINE__, - (scheme == NULL ? "NULL" : "invalid")); - res = CURLE_HTTP_RETURNED_ERROR; -@@ -127,5 +127,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_easy_cleanup(dupe); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1537.c b/tests/libtest/lib1537.c -index 21252fb79..9c991e830 100644 ---- a/tests/libtest/lib1537.c -+++ b/tests/libtest/lib1537.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - const unsigned char a[] = {0x2f, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7}; -@@ -87,5 +87,5 @@ test_cleanup: - curl_free(ptr); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1538.c b/tests/libtest/lib1538.c -index cd9e3f65c..ebc68573f 100644 ---- a/tests/libtest/lib1538.c -+++ b/tests/libtest/lib1538.c -@@ -25,9 +25,9 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURLcode easyret; - CURLMcode multiret; - CURLSHcode shareret; -@@ -56,5 +56,5 @@ int test(char *URL) - printf("u%d: %s\n", (int)urlret, curl_url_strerror(urlret)); - } - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1540.c b/tests/libtest/lib1540.c -index ea1cb1cd1..210879447 100644 ---- a/tests/libtest/lib1540.c -+++ b/tests/libtest/lib1540.c -@@ -23,6 +23,7 @@ - ***************************************************************************/ - #include "test.h" - -+#include "testtrace.h" - #include "testutil.h" - #include "warnless.h" - #include "memdebug.h" -@@ -56,7 +57,7 @@ static int please_continue(void *userp, - return 0; /* go on */ - } - --static size_t header_callback(void *ptr, size_t size, size_t nmemb, -+static size_t header_callback(char *ptr, size_t size, size_t nmemb, - void *userp) - { - size_t len = size * nmemb; -@@ -65,7 +66,7 @@ static size_t header_callback(void *ptr, size_t size, size_t nmemb, - return len; - } - --static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) -+static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp) - { - struct transfer_status *st = (struct transfer_status *)userp; - size_t len = size * nmemb; -@@ -82,10 +83,10 @@ static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) - return CURL_WRITEFUNC_PAUSE; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - struct transfer_status st; - - start_test_timing(); -@@ -107,6 +108,12 @@ int test(char *URL) - easy_setopt(curls, CURLOPT_XFERINFODATA, &st); - easy_setopt(curls, CURLOPT_NOPROGRESS, 0L); - -+ libtest_debug_config.nohex = 1; -+ libtest_debug_config.tracetime = 1; -+ test_setopt(curls, CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(curls, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); -+ easy_setopt(curls, CURLOPT_VERBOSE, 1L); -+ - res = curl_easy_perform(curls); - - test_cleanup: -@@ -114,5 +121,5 @@ test_cleanup: - curl_easy_cleanup(curls); - curl_global_cleanup(); - -- return (int)res; /* return the final return code */ -+ return res; /* return the final return code */ - } -diff --git a/tests/libtest/lib1541.c b/tests/libtest/lib1541.c -index fdb8a04b5..a60d61a7e 100644 ---- a/tests/libtest/lib1541.c -+++ b/tests/libtest/lib1541.c -@@ -77,7 +77,7 @@ static void check_time0(CURL *easy, int key, const char *name, - report_time(name, where, tval, !tval); - } - --static size_t header_callback(void *ptr, size_t size, size_t nmemb, -+static size_t header_callback(char *ptr, size_t size, size_t nmemb, - void *userp) - { - struct transfer_status *st = (struct transfer_status *)userp; -@@ -100,7 +100,7 @@ static size_t header_callback(void *ptr, size_t size, size_t nmemb, - return len; - } - --static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) -+static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userp) - { - struct transfer_status *st = (struct transfer_status *)userp; - -@@ -110,10 +110,10 @@ static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp) - return size * nmemb; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - struct transfer_status st; - - start_test_timing(); -@@ -137,6 +137,7 @@ int test(char *URL) - - check_time(curls, KN(CURLINFO_CONNECT_TIME_T), "done"); - check_time(curls, KN(CURLINFO_PRETRANSFER_TIME_T), "done"); -+ check_time(curls, KN(CURLINFO_POSTTRANSFER_TIME_T), "done"); - check_time(curls, KN(CURLINFO_STARTTRANSFER_TIME_T), "done"); - /* no SSL, must be 0 */ - check_time0(curls, KN(CURLINFO_APPCONNECT_TIME_T), "done"); -@@ -148,5 +149,5 @@ test_cleanup: - curl_easy_cleanup(curls); - curl_global_cleanup(); - -- return (int)res; /* return the final return code */ -+ return res; /* return the final return code */ - } -diff --git a/tests/libtest/lib1542.c b/tests/libtest/lib1542.c -index 2570ea3cf..5a8926585 100644 ---- a/tests/libtest/lib1542.c -+++ b/tests/libtest/lib1542.c -@@ -36,10 +36,10 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1545.c b/tests/libtest/lib1545.c -index f31baa0c4..a1891375b 100644 ---- a/tests/libtest/lib1545.c -+++ b/tests/libtest/lib1545.c -@@ -21,15 +21,12 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ --#ifndef CURL_DISABLE_DEPRECATION --#define CURL_DISABLE_DEPRECATION /* Using and testing the form api */ --#endif - #include "test.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *eh = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - struct curl_httppost *lastptr = NULL; - struct curl_httppost *m_formpost = NULL; - -@@ -38,17 +35,20 @@ int test(char *URL) - easy_init(eh); - - easy_setopt(eh, CURLOPT_URL, URL); -- curl_formadd(&m_formpost, &lastptr, CURLFORM_COPYNAME, "file", -- CURLFORM_FILE, "missing-file", CURLFORM_END); -- curl_easy_setopt(eh, CURLOPT_HTTPPOST, m_formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_formadd(&m_formpost, &lastptr, CURLFORM_COPYNAME, "file", -+ CURLFORM_FILE, "missing-file", CURLFORM_END); -+ curl_easy_setopt(eh, CURLOPT_HTTPPOST, m_formpost); -+ ) - - (void)curl_easy_perform(eh); - (void)curl_easy_perform(eh); - - test_cleanup: - -- curl_formfree(m_formpost); -- -+ CURL_IGNORE_DEPRECATION( -+ curl_formfree(m_formpost); -+ ) - curl_easy_cleanup(eh); - curl_global_cleanup(); - -diff --git a/tests/libtest/lib1550.c b/tests/libtest/lib1550.c -index 4c34be865..ddc0c16ab 100644 ---- a/tests/libtest/lib1550.c -+++ b/tests/libtest/lib1550.c -@@ -27,10 +27,10 @@ - - #include - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *handle; -- int res = CURLE_OK; -+ CURLcode res = CURLE_OK; - static const char * const bl_servers[] = - {"Microsoft-IIS/6.0", "nginx/0.8.54", NULL}; - static const char * const bl_sites[] = -@@ -44,5 +44,5 @@ int test(char *URL) - curl_multi_setopt(handle, CURLMOPT_PIPELINING_SITE_BL, bl_sites); - curl_multi_cleanup(handle); - curl_global_cleanup(); -- return 0; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib1551.c b/tests/libtest/lib1551.c -index 784113aaf..20e938ece 100644 ---- a/tests/libtest/lib1551.c -+++ b/tests/libtest/lib1551.c -@@ -27,7 +27,7 @@ - - #include - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -49,5 +49,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1552.c b/tests/libtest/lib1552.c -index c48d640d6..821fba27a 100644 ---- a/tests/libtest/lib1552.c -+++ b/tests/libtest/lib1552.c -@@ -29,13 +29,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; - CURLM *multi = NULL; - int still_running; -- int i = 0; -- int res = 0; -+ CURLcode i = CURLE_OK; -+ CURLcode res = CURLE_OK; - CURLMsg *msg; - int counter = 3; - -@@ -59,10 +59,11 @@ int test(char *URL) - abort_on_test_timeout(); - - while(still_running && counter--) { -+ CURLMcode mres; - int num; -- res = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -- if(res != CURLM_OK) { -- printf("curl_multi_wait() returned %d\n", res); -+ mres = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -+ if(mres != CURLM_OK) { -+ printf("curl_multi_wait() returned %d\n", mres); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -diff --git a/tests/libtest/lib1553.c b/tests/libtest/lib1553.c -index 8bf15684b..998c0762a 100644 ---- a/tests/libtest/lib1553.c -+++ b/tests/libtest/lib1553.c -@@ -24,6 +24,7 @@ - #include "test.h" - - #include "testutil.h" -+#include "testtrace.h" - #include "warnless.h" - #include "memdebug.h" - -@@ -42,13 +43,13 @@ static int xferinfo(void *p, - return 1; /* fail as fast as we can */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; - CURLM *multi = NULL; - int still_running; -- int i = 0; -- int res = 0; -+ CURLcode i = CURLE_OK; -+ CURLcode res = CURLE_OK; - curl_mimepart *field = NULL; - curl_mime *mime = NULL; - int counter = 1; -@@ -74,6 +75,12 @@ int test(char *URL) - easy_setopt(curls, CURLOPT_XFERINFOFUNCTION, xferinfo); - easy_setopt(curls, CURLOPT_NOPROGRESS, 1L); - -+ libtest_debug_config.nohex = 1; -+ libtest_debug_config.tracetime = 1; -+ test_setopt(curls, CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(curls, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); -+ easy_setopt(curls, CURLOPT_VERBOSE, 1L); -+ - multi_add_handle(multi, curls); - - multi_perform(multi, &still_running); -@@ -81,10 +88,11 @@ int test(char *URL) - abort_on_test_timeout(); - - while(still_running && counter--) { -+ CURLMcode mres; - int num; -- res = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -- if(res != CURLM_OK) { -- printf("curl_multi_wait() returned %d\n", res); -+ mres = curl_multi_wait(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -+ if(mres != CURLM_OK) { -+ printf("curl_multi_wait() returned %d\n", mres); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -diff --git a/tests/libtest/lib1554.c b/tests/libtest/lib1554.c -index 181044d05..3c48f3fe0 100644 ---- a/tests/libtest/lib1554.c -+++ b/tests/libtest/lib1554.c -@@ -24,26 +24,38 @@ - #include "test.h" - #include "memdebug.h" - --static void my_lock(CURL *handle, curl_lock_data data, -- curl_lock_access laccess, void *useptr) -+static const char *ldata_names[] = { -+ "NONE", -+ "SHARE", -+ "COOKIE", -+ "DNS", -+ "SESSION", -+ "CONNECT", -+ "PSL", -+ "HSTS", -+ "NULL", -+}; -+ -+static void test_lock(CURL *handle, curl_lock_data data, -+ curl_lock_access laccess, void *useptr) - { - (void)handle; - (void)data; - (void)laccess; - (void)useptr; -- printf("-> Mutex lock\n"); -+ printf("-> Mutex lock %s\n", ldata_names[data]); - } - --static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) -+static void test_unlock(CURL *handle, curl_lock_data data, void *useptr) - { - (void)handle; - (void)data; - (void)useptr; -- printf("<- Mutex unlock\n"); -+ printf("<- Mutex unlock %s\n", ldata_names[data]); - } - - /* test function */ --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURLSH *share = NULL; -@@ -58,8 +70,8 @@ int test(char *URL) - } - - curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); -- curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); -- curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); -+ curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock); -+ curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock); - - /* Loop the transfer and cleanup the handle properly every lap. This will - still reuse connections since the pool is in the shared object! */ -@@ -91,5 +103,5 @@ test_cleanup: - curl_share_cleanup(share); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1555.c b/tests/libtest/lib1555.c -index 1ff6f28d5..59db1fbdb 100644 ---- a/tests/libtest/lib1555.c -+++ b/tests/libtest/lib1555.c -@@ -53,9 +53,9 @@ static int progressCallback(void *arg, - return 1; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1556.c b/tests/libtest/lib1556.c -index 6f8a21439..25be5e50f 100644 ---- a/tests/libtest/lib1556.c -+++ b/tests/libtest/lib1556.c -@@ -31,7 +31,7 @@ struct headerinfo { - size_t largest; - }; - --static size_t header(void *ptr, size_t size, size_t nmemb, void *stream) -+static size_t header(char *ptr, size_t size, size_t nmemb, void *stream) - { - size_t headersize = size * nmemb; - struct headerinfo *info = (struct headerinfo *)stream; -@@ -44,11 +44,11 @@ static size_t header(void *ptr, size_t size, size_t nmemb, void *stream) - return nmemb * size; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode code; - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - struct headerinfo info = {0}; - - global_init(CURL_GLOBAL_ALL); -@@ -64,7 +64,7 @@ int test(char *URL) - if(CURLE_OK != code) { - fprintf(stderr, "%s:%d curl_easy_perform() failed, " - "with code %d (%s)\n", -- __FILE__, __LINE__, (int)code, curl_easy_strerror(code)); -+ __FILE__, __LINE__, code, curl_easy_strerror(code)); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -diff --git a/tests/libtest/lib1557.c b/tests/libtest/lib1557.c -index 2fa34ada3..6f0b99ac5 100644 ---- a/tests/libtest/lib1557.c -+++ b/tests/libtest/lib1557.c -@@ -27,13 +27,13 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *curlm = NULL; - CURL *curl1 = NULL; - CURL *curl2 = NULL; - int running_handles = 0; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1558.c b/tests/libtest/lib1558.c -index d64b59801..e3a648f39 100644 ---- a/tests/libtest/lib1558.c -+++ b/tests/libtest/lib1558.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *curl = NULL; -@@ -58,7 +58,7 @@ int test(char *URL) - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return 0; -+ return CURLE_OK; - - test_cleanup: - -diff --git a/tests/libtest/lib1559.c b/tests/libtest/lib1559.c -index 402fee3d0..37c0b8aac 100644 ---- a/tests/libtest/lib1559.c -+++ b/tests/libtest/lib1559.c -@@ -28,7 +28,7 @@ - #include "memdebug.h" - - #define EXCESSIVE 10*1000*1000 --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *curl = NULL; -@@ -37,7 +37,7 @@ int test(char *URL) - (void)URL; - - if(!longurl) -- return 1; -+ return (CURLcode)1; - - memset(longurl, 'a', EXCESSIVE); - longurl[EXCESSIVE-1] = 0; -@@ -47,11 +47,11 @@ int test(char *URL) - - res = curl_easy_setopt(curl, CURLOPT_URL, longurl); - printf("CURLOPT_URL %d bytes URL == %d\n", -- EXCESSIVE, (int)res); -+ EXCESSIVE, res); - - res = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, longurl); - printf("CURLOPT_POSTFIELDS %d bytes data == %d\n", -- EXCESSIVE, (int)res); -+ EXCESSIVE, res); - - u = curl_url(); - if(u) { -diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c -index 1509c76a7..d5253a739 100644 ---- a/tests/libtest/lib1560.c -+++ b/tests/libtest/lib1560.c -@@ -31,7 +31,7 @@ - */ - - #include "test.h" --#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) -+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN) - #define USE_IDN - #endif - -@@ -151,6 +151,27 @@ struct clearurlcase { - }; - - static const struct testcase get_parts_list[] ={ -+ {"curl.se", -+ "[10] | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]", -+ CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK}, -+ {"https://curl.se:0/#", -+ "https | [11] | [12] | [13] | curl.se | 0 | / | [16] | ", -+ 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://curl.se/#", -+ "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | ", -+ 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://curl.se/?#", -+ "https | [11] | [12] | [13] | curl.se | [15] | / | | ", -+ 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://curl.se/?", -+ "https | [11] | [12] | [13] | curl.se | [15] | / | | [17]", -+ 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://curl.se/?", -+ "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]", -+ 0, 0, CURLUE_OK}, -+ {"https://curl.se/?#", -+ "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]", -+ 0, 0, CURLUE_OK}, - {"https://curl.se/# ", - "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | %20%20", - CURLU_URLENCODE|CURLU_ALLOW_SPACE, 0, CURLUE_OK}, -@@ -253,7 +274,7 @@ static const struct testcase get_parts_list[] ={ - {"https://user@example.net", - "https | user | [12] | [13] | example.net | [15] | / | [16] | [17]", - 0, 0, CURLUE_OK}, --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - {"ws://example.com/color/?green", - "ws | [11] | [12] | [13] | example.com | [15] | /color/ | green |" - " [17]", -@@ -508,6 +529,23 @@ static const struct testcase get_parts_list[] ={ - }; - - static const struct urltestcase get_url_list[] = { -+ {"example.com", -+ "example.com/", -+ CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK}, -+ {"http://user@example.com?#", -+ "http://user@example.com/?#", -+ 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ /* WHATWG disgrees, it wants "https:/0.0.0.0/" */ -+ {"https://0x.0x.0", "https://0x.0x.0/", 0, 0, CURLUE_OK}, -+ -+ {"https://example.com:000000000000000000000443/foo", -+ "https://example.com/foo", -+ 0, CURLU_NO_DEFAULT_PORT, CURLUE_OK}, -+ {"https://example.com:000000000000000000000/foo", -+ "https://example.com:0/foo", -+ 0, CURLU_NO_DEFAULT_PORT, CURLUE_OK}, -+ {"https://192.0x0000A80001", "https://192.168.0.1/", 0, 0, CURLUE_OK}, -+ {"https://0xffffffff", "https://255.255.255.255/", 0, 0, CURLUE_OK}, - {"https://1.0x1000000", "https://1.0x1000000/", 0, 0, CURLUE_OK}, - {"https://0x7f.1", "https://127.0.0.1/", 0, 0, CURLUE_OK}, - {"https://1.2.3.256.com", "https://1.2.3.256.com/", 0, 0, CURLUE_OK}, -@@ -527,6 +565,10 @@ static const struct urltestcase get_url_list[] = { - {"https://[fe80:0:0:0:409b::]:80/moo", - "https://[fe80::409b:0:0:0]:80/moo", - 0, 0, CURLUE_OK}, -+ /* normalize to lower case */ -+ {"https://[FE80:0:A:0:409B:0:0:0]:80/moo", -+ "https://[fe80:0:a:0:409b::]:80/moo", -+ 0, 0, CURLUE_OK}, - {"https://[::%25fakeit];80/moo", - "", - 0, 0, CURLUE_BAD_PORT_NUMBER}, -@@ -770,6 +812,18 @@ static int checkurl(const char *org, const char *url, const char *out) - 3. Extract all components (not URL) - */ - static const struct setgetcase setget_parts_list[] = { -+ {"https://example.com/", -+ "query=\"\",", -+ "https | [11] | [12] | [13] | example.com | [15] | / | | [17]", -+ 0, 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://example.com/", -+ "fragment=\"\",", -+ "https | [11] | [12] | [13] | example.com | [15] | / | [16] | ", -+ 0, 0, CURLU_GET_EMPTY, CURLUE_OK}, -+ {"https://example.com/", -+ "query=\"\",", -+ "https | [11] | [12] | [13] | example.com | [15] | / | [16] | [17]", -+ 0, 0, 0, CURLUE_OK}, - {"https://example.com", - "path=get,", - "https | [11] | [12] | [13] | example.com | [15] | /get | [16] | [17]", -@@ -788,6 +842,14 @@ static const struct setgetcase setget_parts_list[] = { - - /* !checksrc! disable SPACEBEFORECOMMA 1 */ - static const struct setcase set_parts_list[] = { -+ {"https://example.com/", -+ "host=%43url.se,", -+ "https://%43url.se/", -+ 0, 0, CURLUE_OK, CURLUE_OK}, -+ {"https://example.com/", -+ "host=%25url.se,", -+ "", -+ 0, 0, CURLUE_OK, CURLUE_BAD_HOSTNAME}, - {"https://example.com/?param=value", - "query=\"\",", - "https://example.com/", -@@ -900,8 +962,8 @@ static const struct setcase set_parts_list[] = { - 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER}, - {"https://host:1234/", - "port=0,", -- "https://host:1234/", -- 0, 0, CURLUE_OK, CURLUE_BAD_PORT_NUMBER}, -+ "https://host:0/", -+ 0, 0, CURLUE_OK, CURLUE_OK}, - {"https://host:1234/", - "port=65535,", - "https://host:65535/", -@@ -1081,6 +1143,54 @@ static CURLUcode updateurl(CURLU *u, const char *cmd, unsigned int setflags) - } - - static const struct redircase set_url_list[] = { -+ {"http://example.org/", -+ "../path/././../../moo", -+ "http://example.org/moo", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/", -+ "//example.org/../path/../../", -+ "http://example.org/", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/", -+ "///example.org/../path/../../", -+ "http://example.org/", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ ":23", -+ "http://example.org/foo/:23", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "\\x", -+ "http://example.org/foo/\\x", -+ /* WHATWG disagrees */ -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "#/", -+ "http://example.org/foo/bar#/", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "?/", -+ "http://example.org/foo/bar?/", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "#;?", -+ "http://example.org/foo/bar#;?", -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "#", -+ "http://example.org/foo/bar", -+ /* This happens because the parser removes empty fragments */ -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "?", -+ "http://example.org/foo/bar", -+ /* This happens because the parser removes empty queries */ -+ 0, 0, CURLUE_OK}, -+ {"http://example.org/foo/bar", -+ "?#", -+ "http://example.org/foo/bar", -+ /* This happens because the parser removes empty queries and fragments */ -+ 0, 0, CURLUE_OK}, - {"http://example.com/please/../gimme/%TESTNUMBER?foobar#hello", - "http://example.net/there/it/is/../../tes t case=/%TESTNUMBER0002? yes no", - "http://example.net/there/tes%20t%20case=/%TESTNUMBER0002?+yes+no", -@@ -1663,13 +1773,13 @@ static int huge(void) - char *partp; - msnprintf(total, sizeof(total), - "%s://%s:%s@%s/%s?%s#%s", -- (i == 0)? &bigpart[1] : smallpart, -- (i == 1)? &bigpart[1] : smallpart, -- (i == 2)? &bigpart[1] : smallpart, -- (i == 3)? &bigpart[1] : smallpart, -- (i == 4)? &bigpart[1] : smallpart, -- (i == 5)? &bigpart[1] : smallpart, -- (i == 6)? &bigpart[1] : smallpart); -+ (i == 0) ? &bigpart[1] : smallpart, -+ (i == 1) ? &bigpart[1] : smallpart, -+ (i == 2) ? &bigpart[1] : smallpart, -+ (i == 3) ? &bigpart[1] : smallpart, -+ (i == 4) ? &bigpart[1] : smallpart, -+ (i == 5) ? &bigpart[1] : smallpart, -+ (i == 6) ? &bigpart[1] : smallpart); - rc = curl_url_set(urlp, CURLUPART_URL, total, CURLU_NON_SUPPORT_SCHEME); - if((!i && (rc != CURLUE_BAD_SCHEME)) || - (i && rc)) { -@@ -1755,43 +1865,43 @@ err: - return 1; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - (void)URL; /* not used */ - - if(urldup()) -- return 11; -+ return (CURLcode)11; - - if(setget_parts()) -- return 10; -+ return (CURLcode)10; - - if(get_url()) -- return 3; -+ return (CURLcode)3; - - if(huge()) -- return 9; -+ return (CURLcode)9; - - if(get_nothing()) -- return 7; -+ return (CURLcode)7; - - if(scopeid()) -- return 6; -+ return (CURLcode)6; - - if(append()) -- return 5; -+ return (CURLcode)5; - - if(set_url()) -- return 1; -+ return (CURLcode)1; - - if(set_parts()) -- return 2; -+ return (CURLcode)2; - - if(get_parts()) -- return 4; -+ return (CURLcode)4; - - if(clear_url()) -- return 8; -+ return (CURLcode)8; - - printf("success\n"); -- return 0; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib1564.c b/tests/libtest/lib1564.c -index b10d03441..851d02c40 100644 ---- a/tests/libtest/lib1564.c -+++ b/tests/libtest/lib1564.c -@@ -30,12 +30,12 @@ - #define TEST_HANG_TIMEOUT 60 * 1000 - #define WAKEUP_NUM 10 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *multi = NULL; - int numfds; - int i; -- int res = 0; -+ CURLcode res = CURLE_OK; - struct timeval time_before_wait, time_after_wait; - - (void)URL; -diff --git a/tests/libtest/lib1565.c b/tests/libtest/lib1565.c -index 900395147..b6b8ecf12 100644 ---- a/tests/libtest/lib1565.c -+++ b/tests/libtest/lib1565.c -@@ -38,15 +38,15 @@ - static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - static CURL *pending_handles[CONN_NUM]; - static int pending_num = 0; --static int test_failure = 0; -+static CURLcode test_failure = CURLE_OK; - --static CURLM *multi = NULL; -+static CURLM *testmulti = NULL; - static const char *url; - - static void *run_thread(void *ptr) - { - CURL *easy = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int i; - - (void)ptr; -@@ -72,7 +72,7 @@ static void *run_thread(void *ptr) - - pthread_mutex_unlock(&lock); - -- res_multi_wakeup(multi); -+ res_multi_wakeup(testmulti); - } - - test_cleanup: -@@ -89,12 +89,13 @@ test_cleanup: - return NULL; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - int still_running; - int num; - int i; -- int res = 0; -+ int result; -+ CURLcode res = CURLE_OK; - CURL *started_handles[CONN_NUM]; - int started_num = 0; - int finished_num = 0; -@@ -106,30 +107,30 @@ int test(char *URL) - - global_init(CURL_GLOBAL_ALL); - -- multi_init(multi); -+ multi_init(testmulti); - - url = URL; - -- res = pthread_create(&tid, NULL, run_thread, NULL); -- if(!res) -+ result = pthread_create(&tid, NULL, run_thread, NULL); -+ if(!result) - tid_valid = true; - else { - fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n", -- __FILE__, __LINE__, res); -+ __FILE__, __LINE__, result); - goto test_cleanup; - } - - while(1) { -- multi_perform(multi, &still_running); -+ multi_perform(testmulti, &still_running); - - abort_on_test_timeout(); - -- while((message = curl_multi_info_read(multi, &num))) { -+ while((message = curl_multi_info_read(testmulti, &num))) { - if(message->msg == CURLMSG_DONE) { - res = message->data.result; - if(res) - goto test_cleanup; -- multi_remove_handle(multi, message->easy_handle); -+ multi_remove_handle(testmulti, message->easy_handle); - finished_num++; - } - else { -@@ -145,14 +146,14 @@ int test(char *URL) - if(CONN_NUM == finished_num) - break; - -- multi_poll(multi, NULL, 0, TEST_HANG_TIMEOUT, &num); -+ multi_poll(testmulti, NULL, 0, TEST_HANG_TIMEOUT, &num); - - abort_on_test_timeout(); - - pthread_mutex_lock(&lock); - - while(pending_num > 0) { -- res_multi_add_handle(multi, pending_handles[pending_num - 1]); -+ res_multi_add_handle(testmulti, pending_handles[pending_num - 1]); - if(res) { - pthread_mutex_unlock(&lock); - goto test_cleanup; -@@ -190,7 +191,7 @@ test_cleanup: - if(tid_valid) - pthread_join(tid, NULL); - -- curl_multi_cleanup(multi); -+ curl_multi_cleanup(testmulti); - for(i = 0; i < pending_num; i++) - curl_easy_cleanup(pending_handles[i]); - for(i = 0; i < started_num; i++) -@@ -201,7 +202,7 @@ test_cleanup: - } - - #else /* without pthread, this test doesn't work */ --int test(char *URL) -+CURLcode test(char *URL) - { - (void)URL; - return 0; -diff --git a/tests/libtest/lib1567.c b/tests/libtest/lib1567.c -index 26b438dd0..fae8cc12e 100644 ---- a/tests/libtest/lib1567.c -+++ b/tests/libtest/lib1567.c -@@ -27,7 +27,7 @@ - - #include - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_OK; -@@ -55,5 +55,5 @@ test_cleanup: - curl_url_cleanup(u); - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1568.c b/tests/libtest/lib1568.c -index 78e7e6b8a..383d517a4 100644 ---- a/tests/libtest/lib1568.c -+++ b/tests/libtest/lib1568.c -@@ -26,7 +26,7 @@ - #include "testtrace.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret; - CURL *hnd; -@@ -48,5 +48,5 @@ int test(char *URL) - hnd = NULL; - - curl_global_cleanup(); -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib1569.c b/tests/libtest/lib1569.c -index e24a387e3..767d88168 100644 ---- a/tests/libtest/lib1569.c -+++ b/tests/libtest/lib1569.c -@@ -26,7 +26,7 @@ - #include "testtrace.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *hnd; -@@ -47,5 +47,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(hnd); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1591.c b/tests/libtest/lib1591.c -index 5701e10a9..c0200d542 100644 ---- a/tests/libtest/lib1591.c -+++ b/tests/libtest/lib1591.c -@@ -31,24 +31,24 @@ - #include - #include "memdebug.h" - --static char data [] = "Hello Cloud!\r\n"; -+static char testdata[] = "Hello Cloud!\r\n"; - static size_t consumed = 0; - - static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) - { - size_t amount = nmemb * size; /* Total bytes curl wants */ - -- if(consumed == strlen(data)) { -+ if(consumed == strlen(testdata)) { - return 0; - } - -- if(amount > strlen(data)-consumed) { -- amount = strlen(data); -+ if(amount > strlen(testdata)-consumed) { -+ amount = strlen(testdata); - } - - consumed += amount; - (void)stream; -- memcpy(ptr, data, amount); -+ memcpy(ptr, testdata, amount); - return amount; - } - -@@ -73,7 +73,7 @@ static int trailers_callback(struct curl_slist **list, void *userdata) - } - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -116,5 +116,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1592.c b/tests/libtest/lib1592.c -index 974dd256c..ebfcf74b5 100644 ---- a/tests/libtest/lib1592.c -+++ b/tests/libtest/lib1592.c -@@ -41,7 +41,7 @@ - - #include - --int test(char *URL) -+CURLcode test(char *URL) - { - int stillRunning; - CURLM *multiHandle = NULL; -@@ -103,8 +103,7 @@ int test(char *URL) - start_test_timing(); - mres = curl_multi_remove_handle(multiHandle, curl); - if(mres) { -- fprintf(stderr, "curl_multi_remove_handle() failed, " -- "with code %d\n", (int)res); -+ fprintf(stderr, "curl_multi_remove_handle() failed, with code %d\n", mres); - res = TEST_ERR_MULTI; - goto test_cleanup; - } -@@ -120,5 +119,5 @@ test_cleanup: - curl_multi_cleanup(multiHandle); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1593.c b/tests/libtest/lib1593.c -index b0a91b9fd..f5239fda4 100644 ---- a/tests/libtest/lib1593.c -+++ b/tests/libtest/lib1593.c -@@ -28,12 +28,12 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - struct curl_slist *header = NULL; - long unmet; - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1594.c b/tests/libtest/lib1594.c -index 5346c662a..bf25ffbeb 100644 ---- a/tests/libtest/lib1594.c -+++ b/tests/libtest/lib1594.c -@@ -28,12 +28,12 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - struct curl_slist *header = NULL; - curl_off_t retry; - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_ALL); - -diff --git a/tests/libtest/lib1597.c b/tests/libtest/lib1597.c -index 44769f9cf..fa09e71d6 100644 ---- a/tests/libtest/lib1597.c -+++ b/tests/libtest/lib1597.c -@@ -33,10 +33,10 @@ struct pair { - CURLcode *exp; - }; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - CURLcode result = CURLE_OK; - curl_version_info_data *curlinfo; - const char *const *proto; -@@ -77,7 +77,7 @@ int test(char *URL) - curlinfo = curl_version_info(CURLVERSION_NOW); - if(!curlinfo) { - fputs("curl_version_info failed\n", stderr); -- res = (int) TEST_ERR_FAILURE; -+ res = TEST_ERR_FAILURE; - goto test_cleanup; - } - -@@ -85,7 +85,7 @@ int test(char *URL) - for(proto = curlinfo->protocols; *proto; proto++) { - if((size_t) n >= sizeof(protolist)) { - puts("protolist buffer too small\n"); -- res = (int) TEST_ERR_FAILURE; -+ res = TEST_ERR_FAILURE; - goto test_cleanup; - } - n += msnprintf(protolist + n, sizeof(protolist) - n, ",%s", *proto); -@@ -99,17 +99,15 @@ int test(char *URL) - for(i = 0; prots[i].in; i++) { - result = curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, prots[i].in); - if(result != *prots[i].exp) { -- printf("unexpectedly '%s' returned %u\n", -- prots[i].in, result); -+ printf("unexpectedly '%s' returned %d\n", prots[i].in, result); - break; - } - } - printf("Tested %u strings\n", i); -- res = (int)result; - - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)result; -+ return result; - } -diff --git a/tests/libtest/lib1598.c b/tests/libtest/lib1598.c -index c099116a8..904ba65b0 100644 ---- a/tests/libtest/lib1598.c -+++ b/tests/libtest/lib1598.c -@@ -54,7 +54,7 @@ static int trailers_callback(struct curl_slist **list, void *userdata) - - static const char *post_data = "xxx=yyy&aaa=bbbbb"; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_FAILED_INIT; -@@ -103,5 +103,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1662.c b/tests/libtest/lib1662.c -index 93c080033..1e9e2b061 100644 ---- a/tests/libtest/lib1662.c -+++ b/tests/libtest/lib1662.c -@@ -23,7 +23,7 @@ - ***************************************************************************/ - #include "test.h" - --static char data[]="mooaaa"; -+static char testdata[]="mooaaa"; - - struct WriteThis { - size_t sizeleft; -@@ -32,13 +32,13 @@ struct WriteThis { - static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - { - struct WriteThis *pooh = (struct WriteThis *)userp; -- size_t len = strlen(data); -+ size_t len = strlen(testdata); - - if(size*nmemb < len) - return 0; - - if(pooh->sizeleft) { -- memcpy(ptr, data, strlen(data)); -+ memcpy(ptr, testdata, strlen(testdata)); - pooh->sizeleft = 0; - return len; - } -@@ -47,7 +47,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *hnd; -@@ -86,5 +86,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - curl_mime_free(mime1); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1900.c b/tests/libtest/lib1900.c -index 92f89c4c4..1b26e7b98 100644 ---- a/tests/libtest/lib1900.c -+++ b/tests/libtest/lib1900.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *hnd = NULL; -@@ -45,11 +45,11 @@ int test(char *URL) - curl_easy_cleanup(hnd); - curl_easy_cleanup(second); - curl_global_cleanup(); -- return 0; -+ return CURLE_OK; - - test_cleanup: - curl_easy_cleanup(hnd); - curl_easy_cleanup(second); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1901.c b/tests/libtest/lib1901.c -new file mode 100644 -index 000000000..314f0354d ---- /dev/null -+++ b/tests/libtest/lib1901.c -@@ -0,0 +1,95 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+#include "test.h" -+ -+#include "testutil.h" -+#include "warnless.h" -+#include "memdebug.h" -+ -+ -+ -+static const char *chunks[]={ -+ "one", -+ "two", -+ "three", -+ "four", -+ NULL -+}; -+ -+ -+static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) -+{ -+ static int ix = 0; -+ (void)size; -+ (void)nmemb; -+ (void)stream; -+ if(chunks[ix]) { -+ size_t len = strlen(chunks[ix]); -+ strcpy(ptr, chunks[ix]); -+ ix++; -+ return len; -+ } -+ return 0; -+} -+ -+CURLcode test(char *URL) -+{ -+ CURL *curl; -+ CURLcode res = CURLE_OK; -+ struct curl_slist *chunk = NULL; -+ -+ curl_global_init(CURL_GLOBAL_ALL); -+ -+ curl = curl_easy_init(); -+ if(curl) { -+ /* deliberately setting the size - to a wrong value to make sure libcurl -+ ignores it */ -+ easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 4L); -+ easy_setopt(curl, CURLOPT_POSTFIELDS, NULL); -+ easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); -+ easy_setopt(curl, CURLOPT_POST, 1L); -+ easy_setopt(curl, CURLOPT_VERBOSE, 1L); -+ easy_setopt(curl, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_1_1); -+ easy_setopt(curl, CURLOPT_URL, URL); -+ easy_setopt(curl, CURLOPT_READDATA, NULL); -+ -+ chunk = curl_slist_append(chunk, "Expect:"); -+ if(chunk) { -+ struct curl_slist *n = -+ curl_slist_append(chunk, "Transfer-Encoding: chunked"); -+ if(n) -+ chunk = n; -+ if(n) -+ easy_setopt(curl, CURLOPT_HTTPHEADER, n); -+ } -+ -+ res = curl_easy_perform(curl); -+ } -+test_cleanup: -+ curl_easy_cleanup(curl); -+ curl_slist_free_all(chunk); -+ -+ curl_global_cleanup(); -+ return res; -+} -diff --git a/tests/libtest/lib1903.c b/tests/libtest/lib1903.c -index 3c4ae3073..0ffbb14ad 100644 ---- a/tests/libtest/lib1903.c -+++ b/tests/libtest/lib1903.c -@@ -28,7 +28,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *ch = NULL; -@@ -53,5 +53,5 @@ test_cleanup: - curl_easy_cleanup(ch); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1905.c b/tests/libtest/lib1905.c -index 62b9c60cd..bba0400cb 100644 ---- a/tests/libtest/lib1905.c -+++ b/tests/libtest/lib1905.c -@@ -28,7 +28,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLSH *sh = NULL; - CURL *ch = NULL; -@@ -40,7 +40,7 @@ int test(char *URL) - cm = curl_multi_init(); - if(!cm) { - curl_global_cleanup(); -- return 1; -+ return (CURLcode)1; - } - sh = curl_share_init(); - if(!sh) -@@ -96,5 +96,5 @@ cleanup: - curl_multi_cleanup(cm); - curl_global_cleanup(); - -- return 0; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib1906.c b/tests/libtest/lib1906.c -index b60587f8f..fded3bfb1 100644 ---- a/tests/libtest/lib1906.c -+++ b/tests/libtest/lib1906.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - char *url_after = NULL; -@@ -49,7 +49,7 @@ int test(char *URL) - if(res != CURLE_COULDNT_CONNECT && res != CURLE_OPERATION_TIMEDOUT) { - fprintf(stderr, "failure expected, " - "curl_easy_perform returned %d: <%s>, <%s>\n", -- (int) res, curl_easy_strerror(res), error_buffer); -+ res, curl_easy_strerror(res), error_buffer); - if(res == CURLE_OK) - res = TEST_ERR_MAJOR_BAD; /* force an error return */ - goto test_cleanup; -@@ -68,8 +68,8 @@ int test(char *URL) - res = curl_easy_perform(curl); - if(res) - fprintf(stderr, "success expected, " -- "curl_easy_perform returned %ld: <%s>, <%s>\n", -- (long) res, curl_easy_strerror(res), error_buffer); -+ "curl_easy_perform returned %d: <%s>, <%s>\n", -+ res, curl_easy_strerror(res), error_buffer); - - /* print url */ - curl_url_get(curlu, CURLUPART_URL, &url_after, 0); -@@ -81,5 +81,5 @@ test_cleanup: - curl_url_cleanup(curlu); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1907.c b/tests/libtest/lib1907.c -index 41cea379e..82026f23c 100644 ---- a/tests/libtest/lib1907.c -+++ b/tests/libtest/lib1907.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - char *url_after; - CURL *curl; -@@ -52,5 +52,5 @@ int test(char *URL) - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1908.c b/tests/libtest/lib1908.c -index ff92dafb4..3c7187c5b 100644 ---- a/tests/libtest/lib1908.c -+++ b/tests/libtest/lib1908.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret = CURLE_OK; - CURL *hnd; -@@ -60,5 +60,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - } - curl_global_cleanup(); -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib1910.c b/tests/libtest/lib1910.c -index fed1ca22b..9d3f1b3ab 100644 ---- a/tests/libtest/lib1910.c -+++ b/tests/libtest/lib1910.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret = CURLE_OK; - CURL *hnd; -@@ -45,5 +45,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - } - curl_global_cleanup(); -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib1911.c b/tests/libtest/lib1911.c -index b7c50fc5e..0fd62a8b9 100644 ---- a/tests/libtest/lib1911.c -+++ b/tests/libtest/lib1911.c -@@ -31,9 +31,9 @@ - define not publicly exposed so we set our own */ - #define MAX_INPUT_LENGTH 8000000 - --static char buffer[MAX_INPUT_LENGTH + 2]; -+static char testbuf[MAX_INPUT_LENGTH + 2]; - --int test(char *URL) -+CURLcode test(char *URL) - { - const struct curl_easyoption *o; - CURL *easy; -@@ -44,14 +44,14 @@ int test(char *URL) - easy = curl_easy_init(); - if(!easy) { - curl_global_cleanup(); -- return 1; -+ return (CURLcode)1; - } - - /* make it a null-terminated C string with just As */ -- memset(buffer, 'A', MAX_INPUT_LENGTH + 1); -- buffer[MAX_INPUT_LENGTH + 1] = 0; -+ memset(testbuf, 'A', MAX_INPUT_LENGTH + 1); -+ testbuf[MAX_INPUT_LENGTH + 1] = 0; - -- printf("string length: %d\n", (int)strlen(buffer)); -+ printf("string length: %d\n", (int)strlen(testbuf)); - - for(o = curl_easy_option_next(NULL); - o; -@@ -76,7 +76,7 @@ int test(char *URL) - - /* This is a string. Make sure that passing in a string longer - CURL_MAX_INPUT_LENGTH returns an error */ -- result = curl_easy_setopt(easy, o->id, buffer); -+ result = curl_easy_setopt(easy, o->id, testbuf); - switch(result) { - case CURLE_BAD_FUNCTION_ARGUMENT: /* the most normal */ - case CURLE_UNKNOWN_OPTION: /* left out from the build */ -@@ -86,7 +86,7 @@ int test(char *URL) - default: - /* all other return codes are unexpected */ - fprintf(stderr, "curl_easy_setopt(%s...) returned %d\n", -- o->name, (int)result); -+ o->name, result); - error++; - break; - } -@@ -94,5 +94,5 @@ int test(char *URL) - } - curl_easy_cleanup(easy); - curl_global_cleanup(); -- return error; -+ return error == 0 ? CURLE_OK : TEST_ERR_FAILURE; - } -diff --git a/tests/libtest/lib1912.c b/tests/libtest/lib1912.c -index 13f25bc99..b6667c004 100644 ---- a/tests/libtest/lib1912.c -+++ b/tests/libtest/lib1912.c -@@ -30,7 +30,7 @@ - #define print_err(name, exp) \ - fprintf(stderr, "Type mismatch for CURLOPT_%s (expected %s)\n", name, exp); - --int test(char *URL) -+CURLcode test(char *URL) - { - /* Only test if GCC typechecking is available */ - int error = 0; -@@ -80,5 +80,5 @@ int test(char *URL) - } - #endif - (void)URL; -- return error; -+ return error == 0 ? CURLE_OK : TEST_ERR_FAILURE; - } -diff --git a/tests/libtest/lib1913.c b/tests/libtest/lib1913.c -index a28386368..846842005 100644 ---- a/tests/libtest/lib1913.c -+++ b/tests/libtest/lib1913.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret = CURLE_OK; - CURL *hnd; -@@ -46,5 +46,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - } - curl_global_cleanup(); -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib1915.c b/tests/libtest/lib1915.c -index 0672c70d6..ead6713a0 100644 ---- a/tests/libtest/lib1915.c -+++ b/tests/libtest/lib1915.c -@@ -23,6 +23,7 @@ - ***************************************************************************/ - #include "test.h" - -+#include "testtrace.h" - #include "testutil.h" - #include "warnless.h" - #include "memdebug.h" -@@ -96,7 +97,7 @@ static CURLSTScode hstswrite(CURL *easy, struct curl_hstsentry *e, - * Read/write HSTS cache entries via callback. - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *hnd; -@@ -104,33 +105,46 @@ int test(char *URL) - - global_init(CURL_GLOBAL_ALL); - -+ libtest_debug_config.nohex = 1; -+ libtest_debug_config.tracetime = 1; -+ - easy_init(hnd); - easy_setopt(hnd, CURLOPT_URL, URL); -+ easy_setopt(hnd, CURLOPT_CONNECTTIMEOUT, 1L); - easy_setopt(hnd, CURLOPT_HSTSREADFUNCTION, hstsread); - easy_setopt(hnd, CURLOPT_HSTSREADDATA, &st); - easy_setopt(hnd, CURLOPT_HSTSWRITEFUNCTION, hstswrite); - easy_setopt(hnd, CURLOPT_HSTSWRITEDATA, &st); - easy_setopt(hnd, CURLOPT_HSTS_CTRL, CURLHSTS_ENABLE); -+ easy_setopt(hnd, CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); -+ easy_setopt(hnd, CURLOPT_VERBOSE, 1L); - res = curl_easy_perform(hnd); - curl_easy_cleanup(hnd); - hnd = NULL; -- printf("First request returned %d\n", (int)res); -+ if(res == CURLE_OPERATION_TIMEDOUT) /* we expect that on Windows */ -+ res = CURLE_COULDNT_CONNECT; -+ printf("First request returned %d\n", res); - res = CURLE_OK; - - easy_init(hnd); - easy_setopt(hnd, CURLOPT_URL, URL); -+ easy_setopt(hnd, CURLOPT_CONNECTTIMEOUT, 1L); - easy_setopt(hnd, CURLOPT_HSTSREADFUNCTION, hstsreadfail); - easy_setopt(hnd, CURLOPT_HSTSREADDATA, &st); - easy_setopt(hnd, CURLOPT_HSTSWRITEFUNCTION, hstswrite); - easy_setopt(hnd, CURLOPT_HSTSWRITEDATA, &st); - easy_setopt(hnd, CURLOPT_HSTS_CTRL, CURLHSTS_ENABLE); -+ easy_setopt(hnd, CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, libtest_debug_cb); -+ easy_setopt(hnd, CURLOPT_VERBOSE, 1L); - res = curl_easy_perform(hnd); - curl_easy_cleanup(hnd); - hnd = NULL; -- printf("Second request returned %d\n", (int)res); -+ printf("Second request returned %d\n", res); - - test_cleanup: - curl_easy_cleanup(hnd); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1916.c b/tests/libtest/lib1916.c -index b97263c2e..36a938b61 100644 ---- a/tests/libtest/lib1916.c -+++ b/tests/libtest/lib1916.c -@@ -26,7 +26,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -52,5 +52,5 @@ int test(char *URL) - curl_easy_cleanup(curl); - } - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1918.c b/tests/libtest/lib1918.c -index 34c360889..7eaf41bd4 100644 ---- a/tests/libtest/lib1918.c -+++ b/tests/libtest/lib1918.c -@@ -27,10 +27,9 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - const struct curl_easyoption *o; -- int error = 0; - (void)URL; - - curl_global_init(CURL_GLOBAL_ALL); -@@ -53,5 +52,5 @@ int test(char *URL) - } - } - curl_global_cleanup(); -- return error; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib1919.c b/tests/libtest/lib1919.c -index 37457c068..68ce7a194 100644 ---- a/tests/libtest/lib1919.c -+++ b/tests/libtest/lib1919.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *curl; -@@ -52,5 +52,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1933.c b/tests/libtest/lib1933.c -index cc3af078f..554756c3c 100644 ---- a/tests/libtest/lib1933.c -+++ b/tests/libtest/lib1933.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1934.c b/tests/libtest/lib1934.c -index 36fc8f703..6257759fe 100644 ---- a/tests/libtest/lib1934.c -+++ b/tests/libtest/lib1934.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1935.c b/tests/libtest/lib1935.c -index ee52d4415..8800916c8 100644 ---- a/tests/libtest/lib1935.c -+++ b/tests/libtest/lib1935.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1936.c b/tests/libtest/lib1936.c -index b86eee7bd..c136fc0a2 100644 ---- a/tests/libtest/lib1936.c -+++ b/tests/libtest/lib1936.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1937.c b/tests/libtest/lib1937.c -index 74249666e..61f71127b 100644 ---- a/tests/libtest/lib1937.c -+++ b/tests/libtest/lib1937.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1938.c b/tests/libtest/lib1938.c -index 4b5218bdb..02ab6cc20 100644 ---- a/tests/libtest/lib1938.c -+++ b/tests/libtest/lib1938.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1939.c b/tests/libtest/lib1939.c -index 4adc87669..c7365e5fe 100644 ---- a/tests/libtest/lib1939.c -+++ b/tests/libtest/lib1939.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *multi; - CURL *easy; -diff --git a/tests/libtest/lib1940.c b/tests/libtest/lib1940.c -index 05da9de30..e8dbcdd13 100644 ---- a/tests/libtest/lib1940.c -+++ b/tests/libtest/lib1940.c -@@ -26,7 +26,7 @@ - - #include "memdebug.h" - --static const char *show[]={ -+static const char *testdata[]={ - "daTE", - "Server", - "content-type", -@@ -50,9 +50,9 @@ static void showem(CURL *easy, unsigned int type) - { - int i; - struct curl_header *header; -- for(i = 0; show[i]; i++) { -- if(CURLHE_OK == curl_easy_header(easy, show[i], 0, type, HEADER_REQUEST, -- &header)) { -+ for(i = 0; testdata[i]; i++) { -+ if(CURLHE_OK == curl_easy_header(easy, testdata[i], 0, type, -+ HEADER_REQUEST, &header)) { - if(header->amount > 1) { - /* more than one, iterate over them */ - size_t index = 0; -@@ -63,7 +63,7 @@ static void showem(CURL *easy, unsigned int type) - - if(++index == amount) - break; -- if(CURLHE_OK != curl_easy_header(easy, show[i], index, type, -+ if(CURLHE_OK != curl_easy_header(easy, testdata[i], index, type, - HEADER_REQUEST, &header)) - break; - } while(1); -@@ -83,7 +83,7 @@ static size_t write_cb(char *data, size_t n, size_t l, void *userp) - (void)userp; - return n*l; - } --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - CURLcode res = CURLE_OK; -@@ -116,5 +116,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(easy); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1945.c b/tests/libtest/lib1945.c -index 2483402f4..8cbb01ec6 100644 ---- a/tests/libtest/lib1945.c -+++ b/tests/libtest/lib1945.c -@@ -49,7 +49,7 @@ static size_t write_cb(char *data, size_t n, size_t l, void *userp) - (void)userp; - return n*l; - } --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy; - CURLcode res = CURLE_OK; -@@ -70,12 +70,12 @@ int test(char *URL) - } - res = curl_easy_perform(easy); - if(res) { -- printf("badness: %d\n", (int)res); -+ printf("badness: %d\n", res); - } - showem(easy, CURLH_CONNECT|CURLH_HEADER|CURLH_TRAILER|CURLH_1XX); - - test_cleanup: - curl_easy_cleanup(easy); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1947.c b/tests/libtest/lib1947.c -index c81345f9d..cd14e2661 100644 ---- a/tests/libtest/lib1947.c -+++ b/tests/libtest/lib1947.c -@@ -33,7 +33,7 @@ static size_t writecb(char *data, size_t n, size_t l, void *userp) - (void)userp; - return n*l; - } --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -88,5 +88,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1948.c b/tests/libtest/lib1948.c -index a30244c27..45c7f199b 100644 ---- a/tests/libtest/lib1948.c -+++ b/tests/libtest/lib1948.c -@@ -41,7 +41,7 @@ static size_t put_callback(char *ptr, size_t size, size_t nmemb, void *stream) - return tocopy; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -74,5 +74,5 @@ int test(char *URL) - test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib1955.c b/tests/libtest/lib1955.c -index 3328d7ef1..39b5754ad 100644 ---- a/tests/libtest/lib1955.c -+++ b/tests/libtest/lib1955.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1956.c b/tests/libtest/lib1956.c -index 105418dc8..669e14393 100644 ---- a/tests/libtest/lib1956.c -+++ b/tests/libtest/lib1956.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1957.c b/tests/libtest/lib1957.c -index 8397d9d24..7cc35e42b 100644 ---- a/tests/libtest/lib1957.c -+++ b/tests/libtest/lib1957.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1958.c b/tests/libtest/lib1958.c -index 66b8d5dfd..58b4ea79b 100644 ---- a/tests/libtest/lib1958.c -+++ b/tests/libtest/lib1958.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1959.c b/tests/libtest/lib1959.c -index 5eee4f012..1fbf26c0b 100644 ---- a/tests/libtest/lib1959.c -+++ b/tests/libtest/lib1959.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1960.c b/tests/libtest/lib1960.c -index 9b82128e9..020ee4ba6 100644 ---- a/tests/libtest/lib1960.c -+++ b/tests/libtest/lib1960.c -@@ -68,7 +68,7 @@ static int sockopt_cb(void *clientp, - } - - /* Expected args: URL IP PORT */ --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = TEST_ERR_MAJOR_BAD; -@@ -78,7 +78,7 @@ int test(char *URL) - unsigned short port; - - if(!strcmp("check", URL)) -- return 0; /* no output makes it not skipped */ -+ return CURLE_OK; /* no output makes it not skipped */ - - port = (unsigned short)atoi(libtest_arg3); - -@@ -140,10 +140,10 @@ test_cleanup: - return res; - } - #else --int test(char *URL) -+CURLcode test(char *URL) - { - (void)URL; - printf("lacks inet_pton\n"); -- return 0; -+ return CURLE_OK; - } - #endif -diff --git a/tests/libtest/lib1964.c b/tests/libtest/lib1964.c -index a9881e98d..9e17f926c 100644 ---- a/tests/libtest/lib1964.c -+++ b/tests/libtest/lib1964.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib1970.c b/tests/libtest/lib1970.c -index ff86fdd2c..f0b9d517b 100644 ---- a/tests/libtest/lib1970.c -+++ b/tests/libtest/lib1970.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1971.c b/tests/libtest/lib1971.c -index 173fc2f12..8f4be08b2 100644 ---- a/tests/libtest/lib1971.c -+++ b/tests/libtest/lib1971.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -35,7 +35,7 @@ static size_t read_callback(char *buffer, size_t size, size_t nitems, - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1972.c b/tests/libtest/lib1972.c -index c21e8da93..a51c45018 100644 ---- a/tests/libtest/lib1972.c -+++ b/tests/libtest/lib1972.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - curl_mime *mime = NULL; -diff --git a/tests/libtest/lib1973.c b/tests/libtest/lib1973.c -index d95744fcb..4b2ba95c6 100644 ---- a/tests/libtest/lib1973.c -+++ b/tests/libtest/lib1973.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1974.c b/tests/libtest/lib1974.c -index 948d44df9..41922fa60 100644 ---- a/tests/libtest/lib1974.c -+++ b/tests/libtest/lib1974.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib1975.c b/tests/libtest/lib1975.c -index bca0c763f..0cd9be24b 100644 ---- a/tests/libtest/lib1975.c -+++ b/tests/libtest/lib1975.c -@@ -5,7 +5,7 @@ - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * -- * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -35,7 +35,7 @@ static size_t read_callback(char *buffer, size_t size, size_t nitems, - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = TEST_ERR_MAJOR_BAD; -diff --git a/tests/libtest/lib2301.c b/tests/libtest/lib2301.c -index e654f8166..15615145f 100644 ---- a/tests/libtest/lib2301.c -+++ b/tests/libtest/lib2301.c -@@ -24,21 +24,21 @@ - - #include "test.h" - --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - #if 0 - --static int ping(CURL *curl, const char *send_payload) -+static CURLcode send_ping(CURL *curl, const char *send_payload) - { - size_t sent; - CURLcode result = - curl_ws_send(curl, send_payload, strlen(send_payload), &sent, CURLWS_PING); - fprintf(stderr, -- "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent); -+ "ws: curl_ws_send returned %d, sent %d\n", result, (int)sent); - -- return (int)result; -+ return result; - } - --static int recv_pong(CURL *curl, const char *expected_payload) -+static CURLcode recv_pong(CURL *curl, const char *expected_payload) - { - size_t rlen; - unsigned int rflags; -@@ -58,11 +58,11 @@ static int recv_pong(CURL *curl, const char *expected_payload) - fprintf(stderr, "ws: did NOT get the same payload back\n"); - } - else { -- fprintf(stderr, "recv_pong: got %u bytes rflags %x\n", (int)rlen, rflags); -+ fprintf(stderr, "recv_pong: got %d bytes rflags %x\n", (int)rlen, rflags); - } -- fprintf(stderr, "ws: curl_ws_recv returned %u, received %u\n", (int)result, -- rlen); -- return (int)result; -+ fprintf(stderr, "ws: curl_ws_recv returned %d, received %d\n", result, -+ (int)rlen); -+ return result; - } - - /* just close the connection */ -@@ -72,7 +72,7 @@ static void websocket_close(CURL *curl) - CURLcode result = - curl_ws_send(curl, "", 0, &sent, CURLWS_CLOSE); - fprintf(stderr, -- "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent); -+ "ws: curl_ws_send returned %d, sent %d\n", result, (int)sent); - } - - static void websocket(CURL *curl) -@@ -80,7 +80,7 @@ static void websocket(CURL *curl) - int i = 0; - fprintf(stderr, "ws: websocket() starts\n"); - do { -- if(ping(curl, "foobar")) -+ if(send_ping(curl, "foobar")) - return; - if(recv_pong(curl, "foobar")) - return; -@@ -101,7 +101,7 @@ static size_t writecb(char *b, size_t size, size_t nitems, void *p) - 0x8a, 0x0 - }; - size_t incoming = nitems; -- fprintf(stderr, "Called CURLOPT_WRITEFUNCTION with %u bytes: ", -+ fprintf(stderr, "Called CURLOPT_WRITEFUNCTION with %d bytes: ", - (int)nitems); - for(i = 0; i < nitems; i++) - fprintf(stderr, "%02x ", (unsigned char)buffer[i]); -@@ -119,7 +119,7 @@ static size_t writecb(char *b, size_t size, size_t nitems, void *p) - return nitems; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -137,7 +137,7 @@ int test(char *URL) - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl); - res = curl_easy_perform(curl); -- fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res); -+ fprintf(stderr, "curl_easy_perform() returned %d\n", res); - #if 0 - if(res == CURLE_OK) - websocket(curl); -@@ -146,9 +146,9 @@ int test(char *URL) - curl_easy_cleanup(curl); - } - curl_global_cleanup(); -- return (int)res; -+ return res; - } - --#else /* no websockets */ -+#else /* no WebSockets */ - NO_SUPPORT_BUILT_IN - #endif -diff --git a/tests/libtest/lib2302.c b/tests/libtest/lib2302.c -index 9e2b80044..415ab9ff1 100644 ---- a/tests/libtest/lib2302.c -+++ b/tests/libtest/lib2302.c -@@ -24,7 +24,7 @@ - - #include "test.h" - --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - - struct ws_data { - CURL *easy; -@@ -63,7 +63,7 @@ static size_t add_data(struct ws_data *wd, const char *buf, size_t blen, - if(wd->nwrites > 0) - flush_data(wd); - wd->has_meta = (meta != NULL); -- wd->meta_flags = meta? meta->flags : 0; -+ wd->meta_flags = meta ? meta->flags : 0; - } - - if(wd->blen + blen > sizeof(wd->buf)) { -@@ -91,7 +91,7 @@ static size_t writecb(char *buffer, size_t size, size_t nitems, void *p) - return nitems; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -112,13 +112,13 @@ int test(char *URL) - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ws_data); - res = curl_easy_perform(curl); -- fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res); -+ fprintf(stderr, "curl_easy_perform() returned %d\n", res); - /* always cleanup */ - curl_easy_cleanup(curl); - flush_data(&ws_data); - } - curl_global_cleanup(); -- return (int)res; -+ return res; - } - - #else -diff --git a/tests/libtest/lib2304.c b/tests/libtest/lib2304.c -index a8ee87548..bc8a1f343 100644 ---- a/tests/libtest/lib2304.c -+++ b/tests/libtest/lib2304.c -@@ -24,21 +24,21 @@ - - #include "test.h" - --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - --static int ping(CURL *curl, const char *send_payload) -+static CURLcode send_ping(CURL *curl, const char *send_payload) - { - size_t sent; - CURLcode result = - curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0, - CURLWS_PING); - fprintf(stderr, -- "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent); -+ "ws: curl_ws_send returned %d, sent %d\n", result, (int)sent); - -- return (int)result; -+ return result; - } - --static int recv_pong(CURL *curl, const char *expected_payload) -+static CURLcode recv_pong(CURL *curl, const char *expected_payload) - { - size_t rlen; - const struct curl_ws_frame *meta; -@@ -58,16 +58,16 @@ static int recv_pong(CURL *curl, const char *expected_payload) - fprintf(stderr, "ws: did NOT get the same payload back\n"); - } - else { -- fprintf(stderr, "recv_pong: got %u bytes rflags %x\n", (int)rlen, -+ fprintf(stderr, "recv_pong: got %d bytes rflags %x\n", (int)rlen, - meta->flags); - } - } -- fprintf(stderr, "ws: curl_ws_recv returned %u, received %u\n", (int)result, -+ fprintf(stderr, "ws: curl_ws_recv returned %d, received %d\n", result, - (int)rlen); -- return (int)result; -+ return result; - } - --static int recv_any(CURL *curl) -+static CURLcode recv_any(CURL *curl) - { - size_t rlen; - const struct curl_ws_frame *meta; -@@ -78,7 +78,7 @@ static int recv_any(CURL *curl) - - fprintf(stderr, "recv_any: got %u bytes rflags %x\n", (int)rlen, - meta->flags); -- return 0; -+ return CURLE_OK; - } - - /* just close the connection */ -@@ -88,7 +88,7 @@ static void websocket_close(CURL *curl) - CURLcode result = - curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE); - fprintf(stderr, -- "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent); -+ "ws: curl_ws_send returned %d, sent %u\n", result, (int)sent); - } - - static void websocket(CURL *curl) -@@ -98,7 +98,7 @@ static void websocket(CURL *curl) - do { - recv_any(curl); - fprintf(stderr, "Send ping\n"); -- if(ping(curl, "foobar")) -+ if(send_ping(curl, "foobar")) - return; - fprintf(stderr, "Receive pong\n"); - if(recv_pong(curl, "foobar")) { -@@ -110,7 +110,7 @@ static void websocket(CURL *curl) - websocket_close(curl); - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -126,7 +126,7 @@ int test(char *URL) - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ - res = curl_easy_perform(curl); -- fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res); -+ fprintf(stderr, "curl_easy_perform() returned %d\n", res); - if(res == CURLE_OK) - websocket(curl); - -@@ -134,7 +134,7 @@ int test(char *URL) - curl_easy_cleanup(curl); - } - curl_global_cleanup(); -- return (int)res; -+ return res; - } - - #else -diff --git a/tests/libtest/lib2305.c b/tests/libtest/lib2305.c -index 374423f0f..71ee19496 100644 ---- a/tests/libtest/lib2305.c -+++ b/tests/libtest/lib2305.c -@@ -24,8 +24,9 @@ - - #include "test.h" - #include "testtrace.h" -+#include "memdebug.h" - --#ifdef USE_WEBSOCKETS -+#ifndef CURL_DISABLE_WEBSOCKETS - - /* just close the connection */ - static void websocket_close(CURL *curl) -@@ -34,7 +35,7 @@ static void websocket_close(CURL *curl) - CURLcode result = - curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE); - fprintf(stderr, -- "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent); -+ "ws: curl_ws_send returned %d, sent %d\n", result, (int)sent); - } - - static void websocket(CURL *curl) -@@ -55,10 +56,11 @@ static void websocket(CURL *curl) - if(result == CURLE_AGAIN) - /* crude busy-loop */ - continue; -- printf("curl_ws_recv returned %d\n", (int)result); -+ fclose(save); -+ printf("curl_ws_recv returned %d\n", result); - return; - } -- printf("%u: nread %zu Age %u Flags %x " -+ printf("%d: nread %zu Age %d Flags %x " - "Offset %" CURL_FORMAT_CURL_OFF_T " " - "Bytesleft %" CURL_FORMAT_CURL_OFF_T "\n", - (int)i, -@@ -71,7 +73,7 @@ static void websocket(CURL *curl) - websocket_close(curl); - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -91,7 +93,7 @@ int test(char *URL) - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */ - res = curl_easy_perform(curl); -- fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res); -+ fprintf(stderr, "curl_easy_perform() returned %d\n", res); - if(res == CURLE_OK) - websocket(curl); - -@@ -99,7 +101,7 @@ int test(char *URL) - curl_easy_cleanup(curl); - } - curl_global_cleanup(); -- return (int)res; -+ return res; - } - - #else -diff --git a/tests/libtest/lib2306.c b/tests/libtest/lib2306.c -index 839bdcc0a..cde751933 100644 ---- a/tests/libtest/lib2306.c -+++ b/tests/libtest/lib2306.c -@@ -29,7 +29,7 @@ - - #define URL2 libtest_arg2 - --int test(char *URL) -+CURLcode test(char *URL) - { - /* first a fine GET response, then a bad one */ - CURL *cl; -diff --git a/tests/libtest/lib2308.c b/tests/libtest/lib2308.c -new file mode 100644 -index 000000000..47e0763c8 ---- /dev/null -+++ b/tests/libtest/lib2308.c -@@ -0,0 +1,54 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+ -+#include "test.h" -+#include "testtrace.h" -+ -+#include -+ -+static size_t cb_curl(char *buffer, size_t size, size_t nmemb, void *userp) -+{ -+ (void)buffer; -+ (void)size; -+ (void)nmemb; -+ (void)userp; -+ return CURL_WRITEFUNC_ERROR; -+} -+ -+CURLcode test(char *URL) -+{ -+ CURL *curl; -+ CURLcode res = CURLE_OK; -+ -+ global_init(CURL_GLOBAL_ALL); -+ curl = curl_easy_init(); -+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb_curl); -+ curl_easy_setopt(curl, CURLOPT_URL, URL); -+ res = curl_easy_perform(curl); -+ printf("Returned %d, should be %d.\n", res, CURLE_WRITE_ERROR); -+ fflush(stdout); -+ curl_easy_cleanup(curl); -+ curl_global_cleanup(); -+ return CURLE_OK; -+} -diff --git a/tests/libtest/lib2402.c b/tests/libtest/lib2402.c -index ab20f92c0..c58946bb1 100644 ---- a/tests/libtest/lib2402.c -+++ b/tests/libtest/lib2402.c -@@ -31,9 +31,9 @@ - - #define NUM_HANDLES 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES] = {0}; - int running; - CURLM *m = NULL; -diff --git a/tests/libtest/lib2404.c b/tests/libtest/lib2404.c -index 1a282ffe2..ed47d4257 100644 ---- a/tests/libtest/lib2404.c -+++ b/tests/libtest/lib2404.c -@@ -31,9 +31,9 @@ - - #define NUM_HANDLES 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES] = {0}; - int running; - CURLM *m = NULL; -diff --git a/tests/libtest/lib2405.c b/tests/libtest/lib2405.c -new file mode 100644 -index 000000000..5b01cd8ce ---- /dev/null -+++ b/tests/libtest/lib2405.c -@@ -0,0 +1,310 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Dmitry Karpov -+ * -+ * 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 -+ * -+ ***************************************************************************/ -+ -+/* -+ * The purpose of this test is to test behavior of curl_multi_waitfds -+ * function in different scenarios: -+ * empty multi handle (expected zero descriptors), -+ * HTTP1 amd HTTP2 (no multiplexing) two transfers (expected two descriptors), -+ * HTTP2 with multiplexing (expected one descriptors) -+ * -+ * It is also expected that all transfers run by multi-handle should complete -+ * successfully. -+ */ -+ -+#include "test.h" -+ -+#include "testutil.h" -+#include "warnless.h" -+#include "memdebug.h" -+ -+ -+ /* ---------------------------------------------------------------- */ -+ -+#define test_check(expected_fds) \ -+ if(res != CURLE_OK) { \ -+ fprintf(stderr, "test failed with code: %d\n", res); \ -+ goto test_cleanup; \ -+ } \ -+ else if(fd_count != expected_fds) { \ -+ fprintf(stderr, "Max number of waitfds: %d not as expected: %d\n", \ -+ fd_count, expected_fds); \ -+ res = TEST_ERR_FAILURE; \ -+ goto test_cleanup; \ -+ } -+ -+#define test_run_check(option, expected_fds) do { \ -+ res = test_run(URL, option, &fd_count); \ -+ test_check(expected_fds); \ -+} while(0) -+ -+ /* ---------------------------------------------------------------- */ -+ -+enum { -+ TEST_USE_HTTP1 = 0, -+ TEST_USE_HTTP2, -+ TEST_USE_HTTP2_MPLEX -+}; -+ -+static size_t emptyWriteFunc(void *ptr, size_t size, size_t nmemb, -+ void *data) { -+ (void)ptr; (void)data; -+ return size * nmemb; -+} -+ -+static CURLcode set_easy(char *URL, CURL *easy, long option) -+{ -+ CURLcode res = CURLE_OK; -+ -+ /* First set the URL that is about to receive our POST. */ -+ easy_setopt(easy, CURLOPT_URL, URL); -+ -+ /* get verbose debug output please */ -+ easy_setopt(easy, CURLOPT_VERBOSE, 1L); -+ -+ switch(option) { -+ case TEST_USE_HTTP1: -+ /* go http1 */ -+ easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); -+ break; -+ -+ case TEST_USE_HTTP2: -+ /* go http2 */ -+ easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); -+ break; -+ -+ case TEST_USE_HTTP2_MPLEX: -+ /* go http2 with multiplexing */ -+ easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); -+ easy_setopt(easy, CURLOPT_PIPEWAIT, 1L); -+ break; -+ } -+ -+ /* no peer verify */ -+ easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L); -+ easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, 0L); -+ -+ /* include headers */ -+ easy_setopt(easy, CURLOPT_HEADER, 1L); -+ -+ /* empty write function */ -+ easy_setopt(easy, CURLOPT_WRITEFUNCTION, emptyWriteFunc); -+ -+test_cleanup: -+ return res; -+} -+ -+static CURLcode test_run(char *URL, long option, unsigned int *max_fd_count) -+{ -+ CURLMcode mc = CURLM_OK; -+ CURLM *multi = NULL; -+ CURLM *multi1 = NULL; -+ -+ CURL *easy1 = NULL; -+ CURL *easy2 = NULL; -+ -+ unsigned int max_count = 0; -+ -+ int still_running; /* keep number of running handles */ -+ CURLMsg *msg; /* for picking up messages with the transfer status */ -+ int msgs_left; /* how many messages are left */ -+ -+ CURLcode result; -+ CURLcode res = CURLE_OK; -+ -+ struct curl_waitfd ufds[10]; -+ struct curl_waitfd ufds1[10]; -+ int numfds; -+ -+ easy_init(easy1); -+ easy_init(easy2); -+ -+ if(set_easy(URL, easy1, option) != CURLE_OK) -+ goto test_cleanup; -+ -+ if(set_easy(URL, easy2, option) != CURLE_OK) -+ goto test_cleanup; -+ -+ multi_init(multi); -+ multi_init(multi1); -+ -+ if(option == TEST_USE_HTTP2_MPLEX) -+ multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); -+ -+ multi_add_handle(multi, easy1); -+ multi_add_handle(multi, easy2); -+ -+ while(!mc) { -+ /* get the count of file descriptors from the transfers */ -+ unsigned int fd_count = 0; -+ -+ mc = curl_multi_perform(multi, &still_running); -+ if(!still_running || mc != CURLM_OK) -+ break; -+ -+ mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); -+ res = TEST_ERR_FAILURE; -+ break; -+ } -+ -+ if(!fd_count) -+ continue; /* no descriptors yet */ -+ -+ /* checking case when we don't have enough space for waitfds */ -+ mc = curl_multi_waitfds(multi, ufds1, fd_count - 1, NULL); -+ -+ if(mc != CURLM_OUT_OF_MEMORY) { -+ fprintf(stderr, "curl_multi_waitfds() return code %d instead of " -+ "CURLM_OUT_OF_MEMORY.\n", mc); -+ res = TEST_ERR_FAILURE; -+ break; -+ } -+ -+ if(fd_count > max_count) -+ max_count = fd_count; -+ -+ /* Do polling on descriptors in ufds in Multi 1 */ -+ mc = curl_multi_poll(multi1, ufds, fd_count, 500, &numfds); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_poll() failed, code %d.\\n", mc); -+ res = TEST_ERR_FAILURE; -+ break; -+ } -+ } -+ -+ for(;;) { -+ msg = curl_multi_info_read(multi, &msgs_left); -+ if(!msg) -+ break; -+ if(msg->msg == CURLMSG_DONE) { -+ result = msg->data.result; -+ -+ if(!res) -+ res = result; -+ } -+ } -+ -+ curl_multi_remove_handle(multi, easy1); -+ curl_multi_remove_handle(multi, easy2); -+ -+test_cleanup: -+ curl_easy_cleanup(easy1); -+ curl_easy_cleanup(easy2); -+ -+ curl_multi_cleanup(multi); -+ curl_multi_cleanup(multi1); -+ -+ if(max_fd_count) -+ *max_fd_count = max_count; -+ -+ return res; -+} -+ -+static CURLcode empty_multi_test(void) -+{ -+ CURLMcode mc = CURLM_OK; -+ CURLM *multi = NULL; -+ CURL *easy = NULL; -+ -+ struct curl_waitfd ufds[10]; -+ -+ CURLcode res = CURLE_OK; -+ unsigned int fd_count = 0; -+ -+ multi_init(multi); -+ -+ /* calling curl_multi_waitfds() on an empty multi handle. */ -+ mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); -+ res = TEST_ERR_FAILURE; -+ goto test_cleanup; -+ } -+ else if(fd_count > 0) { -+ fprintf(stderr, "curl_multi_waitfds() returned non-zero count of " -+ "waitfds: %d.\n", fd_count); -+ res = TEST_ERR_FAILURE; -+ goto test_cleanup; -+ } -+ -+ /* calling curl_multi_waitfds() on multi handle with added easy handle. */ -+ easy_init(easy); -+ -+ if(set_easy((char *)"http://example.com", easy, TEST_USE_HTTP1) != CURLE_OK) -+ goto test_cleanup; -+ -+ multi_add_handle(multi, easy); -+ -+ mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); -+ -+ if(mc != CURLM_OK) { -+ fprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); -+ res = TEST_ERR_FAILURE; -+ goto test_cleanup; -+ } -+ else if(fd_count > 0) { -+ fprintf(stderr, "curl_multi_waitfds() returned non-zero count of " -+ "waitfds: %d.\n", fd_count); -+ res = TEST_ERR_FAILURE; -+ goto test_cleanup; -+ } -+ -+ curl_multi_remove_handle(multi, easy); -+ -+test_cleanup: -+ curl_easy_cleanup(easy); -+ curl_multi_cleanup(multi); -+ return res; -+} -+ -+CURLcode test(char *URL) -+{ -+ CURLcode res = CURLE_OK; -+ unsigned int fd_count = 0; -+ -+ global_init(CURL_GLOBAL_ALL); -+ -+ /* Testing curl_multi_waitfds on empty and not started handles */ -+ res = empty_multi_test(); -+ if(res != CURLE_OK) -+ goto test_cleanup; -+ -+ /* HTTP1, expected 2 waitfds - one for each transfer */ -+ test_run_check(TEST_USE_HTTP1, 2); -+ -+ /* HTTP2, expected 2 waitfds - one for each transfer */ -+ test_run_check(TEST_USE_HTTP2, 2); -+ -+ /* HTTP2 with multiplexing, expected 1 waitfds - one for all transfers */ -+ test_run_check(TEST_USE_HTTP2_MPLEX, 1); -+ -+test_cleanup: -+ curl_global_cleanup(); -+ return res; -+} -diff --git a/tests/libtest/lib2502.c b/tests/libtest/lib2502.c -index e5a7061b0..f01fbe0c5 100644 ---- a/tests/libtest/lib2502.c -+++ b/tests/libtest/lib2502.c -@@ -23,6 +23,7 @@ - ***************************************************************************/ - #include "test.h" - -+#include "testtrace.h" - #include "testutil.h" - #include "warnless.h" - #include "memdebug.h" -@@ -31,9 +32,9 @@ - - #define NUM_HANDLES 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES] = {0}; - int running; - CURLM *m = NULL; -@@ -80,6 +81,10 @@ int test(char *URL) - /* wait for first connection established to see if we can share it */ - easy_setopt(curl[i], CURLOPT_PIPEWAIT, 1L); - /* go verbose */ -+ libtest_debug_config.nohex = 1; -+ libtest_debug_config.tracetime = 0; -+ test_setopt(curl[i], CURLOPT_DEBUGDATA, &libtest_debug_config); -+ easy_setopt(curl[i], CURLOPT_DEBUGFUNCTION, libtest_debug_cb); - easy_setopt(curl[i], CURLOPT_VERBOSE, 1L); - /* include headers */ - easy_setopt(curl[i], CURLOPT_HEADER, 1L); -diff --git a/tests/libtest/lib3010.c b/tests/libtest/lib3010.c -index 598b79fcc..ce0fa3050 100644 ---- a/tests/libtest/lib3010.c -+++ b/tests/libtest/lib3010.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret = CURLE_OK; - CURL *curl = NULL; -diff --git a/tests/libtest/lib3025.c b/tests/libtest/lib3025.c -index f3e3f9208..80f80eae0 100644 ---- a/tests/libtest/lib3025.c -+++ b/tests/libtest/lib3025.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -57,5 +57,5 @@ test_cleanup: - curl_slist_free_all(icy); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib3026.c b/tests/libtest/lib3026.c -index 6f31dabde..61c70eb3b 100644 ---- a/tests/libtest/lib3026.c -+++ b/tests/libtest/lib3026.c -@@ -29,7 +29,7 @@ - #define NUM_THREADS 100 - - #ifdef _WIN32 --#ifdef _WIN32_WCE -+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) - static DWORD WINAPI run_thread(LPVOID ptr) - #else - #include -@@ -45,9 +45,9 @@ static unsigned int WINAPI run_thread(void *ptr) - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { --#ifdef _WIN32_WCE -+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) - typedef HANDLE curl_win_thread_handle_t; - #else - typedef uintptr_t curl_win_thread_handle_t; -@@ -64,7 +64,7 @@ int test(char *URL) - fprintf(stderr, "%s:%d On Windows but the " - "CURL_VERSION_THREADSAFE feature flag is not set\n", - __FILE__, __LINE__); -- return -1; -+ return (CURLcode)-1; - } - - /* On Windows libcurl global init/cleanup calls LoadLibrary/FreeLibrary for -@@ -78,7 +78,7 @@ int test(char *URL) - for(i = 0; i < tid_count; i++) { - curl_win_thread_handle_t th; - results[i] = CURL_LAST; /* initialize with invalid value */ --#ifdef _WIN32_WCE -+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) - th = CreateThread(NULL, 0, run_thread, &results[i], 0, NULL); - #else - th = _beginthreadex(NULL, 0, run_thread, &results[i], 0, NULL); -@@ -105,7 +105,7 @@ cleanup: - } - } - -- return test_failure; -+ return (CURLcode)test_failure; - } - - #elif defined(HAVE_PTHREAD_H) -@@ -123,12 +123,12 @@ static void *run_thread(void *ptr) - return NULL; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode results[NUM_THREADS]; - pthread_t tids[NUM_THREADS]; - unsigned tid_count = NUM_THREADS, i; -- int test_failure = 0; -+ CURLcode test_failure = CURLE_OK; - curl_version_info_data *ver; - (void) URL; - -@@ -137,7 +137,7 @@ int test(char *URL) - fprintf(stderr, "%s:%d Have pthread but the " - "CURL_VERSION_THREADSAFE feature flag is not set\n", - __FILE__, __LINE__); -- return -1; -+ return (CURLcode)-1; - } - - for(i = 0; i < tid_count; i++) { -@@ -148,7 +148,7 @@ int test(char *URL) - fprintf(stderr, "%s:%d Couldn't create thread, errno %d\n", - __FILE__, __LINE__, res); - tid_count = i; -- test_failure = -1; -+ test_failure = (CURLcode)-1; - goto cleanup; - } - } -@@ -160,7 +160,7 @@ cleanup: - fprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," - "with code %d (%s)\n", __FILE__, __LINE__, - i, (int) results[i], curl_easy_strerror(results[i])); -- test_failure = -1; -+ test_failure = (CURLcode)-1; - } - } - -@@ -168,7 +168,7 @@ cleanup: - } - - #else /* without pthread or Windows, this test doesn't work */ --int test(char *URL) -+CURLcode test(char *URL) - { - curl_version_info_data *ver; - (void)URL; -@@ -178,8 +178,8 @@ int test(char *URL) - fprintf(stderr, "%s:%d No pthread but the " - "CURL_VERSION_THREADSAFE feature flag is set\n", - __FILE__, __LINE__); -- return -1; -+ return (CURLcode)-1; - } -- return 0; -+ return CURLE_OK; - } - #endif -diff --git a/tests/libtest/lib3027.c b/tests/libtest/lib3027.c -index 6808f29fd..4ddee1b6b 100644 ---- a/tests/libtest/lib3027.c -+++ b/tests/libtest/lib3027.c -@@ -27,7 +27,7 @@ - #include "warnless.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode ret = CURLE_OK; - CURL *hnd; -@@ -52,5 +52,5 @@ int test(char *URL) - curl_easy_cleanup(hnd); - } - curl_global_cleanup(); -- return (int)ret; -+ return ret; - } -diff --git a/tests/libtest/lib3100.c b/tests/libtest/lib3100.c -index a508d5c7a..82132b947 100644 ---- a/tests/libtest/lib3100.c -+++ b/tests/libtest/lib3100.c -@@ -24,9 +24,9 @@ - #include "test.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { -@@ -54,7 +54,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_DESCRIBE); - - res = curl_easy_perform(curl); -- if(res != (int)CURLE_OK) { -+ if(res != CURLE_OK) { - fprintf(stderr, "Failed to send DESCRIBE: %d\n", res); - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; -diff --git a/tests/libtest/lib3101.c b/tests/libtest/lib3101.c -index dbcf3a6c7..3f2e97711 100644 ---- a/tests/libtest/lib3101.c -+++ b/tests/libtest/lib3101.c -@@ -24,9 +24,9 @@ - #include "test.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { -@@ -51,7 +51,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "https"); - - res = curl_easy_perform(curl); -- if(res != (int)CURLE_OK) { -+ if(res != CURLE_OK) { - res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } -diff --git a/tests/libtest/lib3102.c b/tests/libtest/lib3102.c -index abc0a27ea..7f1b05627 100644 ---- a/tests/libtest/lib3102.c -+++ b/tests/libtest/lib3102.c -@@ -88,7 +88,7 @@ static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) - return size * nmemb; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib3103.c b/tests/libtest/lib3103.c -index 01d62f658..8d6028499 100644 ---- a/tests/libtest/lib3103.c -+++ b/tests/libtest/lib3103.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURLSH *share; -@@ -59,8 +59,8 @@ test_cleanup: - - /* always cleanup */ - curl_easy_cleanup(curl); -- curl_share_cleanup(share); -+ curl_share_cleanup(share); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib3207.c b/tests/libtest/lib3207.c -new file mode 100644 -index 000000000..a78608156 ---- /dev/null -+++ b/tests/libtest/lib3207.c -@@ -0,0 +1,231 @@ -+/*************************************************************************** -+ * _ _ ____ _ -+ * Project ___| | | | _ \| | -+ * / __| | | | |_) | | -+ * | (__| |_| | _ <| |___ -+ * \___|\___/|_| \_\_____| -+ * -+ * Copyright (C) Daniel Stenberg, , 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 -+ * -+ ***************************************************************************/ -+#include "test.h" -+#include "testutil.h" -+#include "memdebug.h" -+ -+#include -+ -+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -+#if defined(USE_THREADS_POSIX) -+#include -+#endif -+#include "curl_threads.h" -+#endif -+ -+#define CAINFO libtest_arg2 -+#define THREAD_SIZE 16 -+#define PER_THREAD_SIZE 8 -+ -+struct Ctx { -+ const char *URL; -+ CURLSH *share; -+ int result; -+ int thread_id; -+ struct curl_slist *contents; -+}; -+ -+static size_t write_memory_callback(char *contents, size_t size, -+ size_t nmemb, void *userp) -+{ -+ /* append the data to contents */ -+ size_t realsize = size * nmemb; -+ struct Ctx *mem = (struct Ctx *)userp; -+ char *data = (char *)malloc(realsize + 1); -+ struct curl_slist *item_append = NULL; -+ if(!data) { -+ printf("not enough memory (malloc returned NULL)\n"); -+ return 0; -+ } -+ memcpy(data, contents, realsize); -+ data[realsize] = '\0'; -+ item_append = curl_slist_append(mem->contents, data); -+ free(data); -+ if(item_append) { -+ mem->contents = item_append; -+ } -+ else { -+ printf("not enough memory (curl_slist_append returned NULL)\n"); -+ return 0; -+ } -+ return realsize; -+} -+ -+static -+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) -+DWORD -+#else -+unsigned int -+#endif -+CURL_STDCALL -+#else -+unsigned int -+#endif -+test_thread(void *ptr) -+{ -+ struct Ctx *ctx = (struct Ctx *)ptr; -+ CURLcode res = CURLE_OK; -+ -+ int i; -+ -+ /* Loop the transfer and cleanup the handle properly every lap. This will -+ still reuse ssl session since the pool is in the shared object! */ -+ for(i = 0; i < PER_THREAD_SIZE; i++) { -+ CURL *curl = curl_easy_init(); -+ if(curl) { -+ curl_easy_setopt(curl, CURLOPT_URL, (char *)ctx->URL); -+ -+ /* use the share object */ -+ curl_easy_setopt(curl, CURLOPT_SHARE, ctx->share); -+ curl_easy_setopt(curl, CURLOPT_CAINFO, CAINFO); -+ -+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_memory_callback); -+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); -+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); -+ -+ /* Perform the request, res will get the return code */ -+ res = curl_easy_perform(curl); -+ -+ /* always cleanup */ -+ curl_easy_cleanup(curl); -+ /* Check for errors */ -+ if(res != CURLE_OK) { -+ fprintf(stderr, "curl_easy_perform() failed: %s\n", -+ curl_easy_strerror(res)); -+ goto test_cleanup; -+ } -+ } -+ } -+ -+test_cleanup: -+ ctx->result = (int)res; -+ return 0; -+} -+ -+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -+ -+static void test_lock(CURL *handle, curl_lock_data data, -+ curl_lock_access laccess, void *useptr) -+{ -+ curl_mutex_t *mutexes = (curl_mutex_t*) useptr; -+ (void)handle; -+ (void)laccess; -+ Curl_mutex_acquire(&mutexes[data]); -+} -+ -+static void test_unlock(CURL *handle, curl_lock_data data, void *useptr) -+{ -+ curl_mutex_t *mutexes = (curl_mutex_t*) useptr; -+ (void)handle; -+ Curl_mutex_release(&mutexes[data]); -+} -+ -+static void execute(CURLSH *share, struct Ctx *ctx) -+{ -+ int i; -+ curl_mutex_t mutexes[CURL_LOCK_DATA_LAST - 1]; -+ curl_thread_t thread[THREAD_SIZE]; -+ for(i = 0; i < CURL_LOCK_DATA_LAST - 1; i++) { -+ Curl_mutex_init(&mutexes[i]); -+ } -+ curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock); -+ curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock); -+ curl_share_setopt(share, CURLSHOPT_USERDATA, (void *)mutexes); -+ curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); -+ -+ for(i = 0; i < THREAD_SIZE; i++) { -+ thread[i] = Curl_thread_create(test_thread, (void *)&ctx[i]); -+ } -+ for(i = 0; i < THREAD_SIZE; i++) { -+ if(thread[i]) { -+ Curl_thread_join(&thread[i]); -+ Curl_thread_destroy(thread[i]); -+ } -+ } -+ curl_share_setopt(share, CURLSHOPT_LOCKFUNC, NULL); -+ curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, NULL); -+ for(i = 0; i < CURL_LOCK_DATA_LAST - 1; i++) { -+ Curl_mutex_destroy(&mutexes[i]); -+ } -+} -+ -+#else /* without pthread, run serially */ -+ -+static void execute(CURLSH *share, struct Ctx *ctx) -+{ -+ int i; -+ (void) share; -+ for(i = 0; i < THREAD_SIZE; i++) { -+ test_thread((void *)&ctx[i]); -+ } -+} -+ -+#endif -+ -+CURLcode test(char *URL) -+{ -+ int res = 0; -+ int i; -+ CURLSH* share; -+ struct Ctx ctx[THREAD_SIZE]; -+ -+ curl_global_init(CURL_GLOBAL_ALL); -+ -+ share = curl_share_init(); -+ if(!share) { -+ fprintf(stderr, "curl_share_init() failed\n"); -+ goto test_cleanup; -+ } -+ -+ for(i = 0; i < THREAD_SIZE; i++) { -+ ctx[i].share = share; -+ ctx[i].URL = URL; -+ ctx[i].thread_id = i; -+ ctx[i].result = 0; -+ ctx[i].contents = NULL; -+ } -+ -+ execute(share, ctx); -+ -+ for(i = 0; i < THREAD_SIZE; i++) { -+ if(ctx[i].result) { -+ res = ctx[i].result; -+ } -+ else { -+ struct curl_slist *item = ctx[i].contents; -+ while(item) { -+ printf("%s", item->data); -+ item = item->next; -+ } -+ } -+ curl_slist_free_all(ctx[i].contents); -+ } -+ -+test_cleanup: -+ if(share) -+ curl_share_cleanup(share); -+ curl_global_cleanup(); -+ return (CURLcode)res; -+} -diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c -index f99b244b4..9aa346669 100644 ---- a/tests/libtest/lib500.c -+++ b/tests/libtest/lib500.c -@@ -28,7 +28,7 @@ - - #ifdef LIB585 - --static int counter; -+static int testcounter; - - static curl_socket_t tst_opensocket(void *clientp, - curlsocktype purpose, -@@ -36,14 +36,14 @@ static curl_socket_t tst_opensocket(void *clientp, - { - (void)clientp; - (void)purpose; -- printf("[OPEN] counter: %d\n", ++counter); -+ printf("[OPEN] counter: %d\n", ++testcounter); - return socket(addr->family, addr->socktype, addr->protocol); - } - - static int tst_closesocket(void *clientp, curl_socket_t sock) - { - (void)clientp; -- printf("[CLOSE] counter: %d\n", counter--); -+ printf("[CLOSE] counter: %d\n", testcounter--); - return sclose(sock); - } - -@@ -51,7 +51,7 @@ static void setupcallbacks(CURL *curl) - { - curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, tst_opensocket); - curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, tst_closesocket); -- counter = 0; -+ testcounter = 0; - } - - #else -@@ -59,7 +59,7 @@ static void setupcallbacks(CURL *curl) - #endif - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -101,6 +101,7 @@ int test(char *URL) - curl_off_t time_namelookup; - curl_off_t time_connect; - curl_off_t time_pretransfer; -+ curl_off_t time_posttransfer; - curl_off_t time_starttransfer; - curl_off_t time_total; - fprintf(moo, "IP %s\n", ipstr); -@@ -108,6 +109,8 @@ int test(char *URL) - curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME_T, &time_connect); - curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME_T, - &time_pretransfer); -+ curl_easy_getinfo(curl, CURLINFO_POSTTRANSFER_TIME_T, -+ &time_posttransfer); - curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME_T, - &time_starttransfer); - curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &time_total); -@@ -128,6 +131,14 @@ int test(char *URL) - (time_pretransfer / 1000000), - (long)(time_pretransfer % 1000000)); - } -+ if(time_pretransfer > time_posttransfer) { -+ fprintf(moo, "pretransfer vs posttransfer: %" CURL_FORMAT_CURL_OFF_T -+ ".%06ld %" CURL_FORMAT_CURL_OFF_T ".%06ld\n", -+ (time_pretransfer / 1000000), -+ (long)(time_pretransfer % 1000000), -+ (time_posttransfer / 1000000), -+ (long)(time_posttransfer % 1000000)); -+ } - if(time_pretransfer > time_starttransfer) { - fprintf(moo, "pretransfer vs starttransfer: %" CURL_FORMAT_CURL_OFF_T - ".%06ld %" CURL_FORMAT_CURL_OFF_T ".%06ld\n", -@@ -143,6 +154,13 @@ int test(char *URL) - (long)(time_starttransfer % 1000000), - (time_total / 1000000), (long)(time_total % 1000000)); - } -+ if(time_posttransfer > time_total) { -+ fprintf(moo, "posttransfer vs total: %" CURL_FORMAT_CURL_OFF_T -+ ".%06ld %" CURL_FORMAT_CURL_OFF_T ".%06ld\n", -+ (time_posttransfer / 1000000), -+ (long)(time_posttransfer % 1000000), -+ (time_total / 1000000), (long)(time_total % 1000000)); -+ } - - fclose(moo); - } -@@ -154,5 +172,7 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -+ -+#undef setupcallbacks -diff --git a/tests/libtest/lib501.c b/tests/libtest/lib501.c -index 7ef850110..94c9adb48 100644 ---- a/tests/libtest/lib501.c -+++ b/tests/libtest/lib501.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -56,5 +56,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib502.c b/tests/libtest/lib502.c -index 91f96e6f5..44ad6f679 100644 ---- a/tests/libtest/lib502.c -+++ b/tests/libtest/lib502.c -@@ -33,11 +33,11 @@ - * Get a single URL without select(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *c = NULL; - CURLM *m = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int running; - - start_test_timing(); -diff --git a/tests/libtest/lib503.c b/tests/libtest/lib503.c -index 15b09476e..cac2a755c 100644 ---- a/tests/libtest/lib503.c -+++ b/tests/libtest/lib503.c -@@ -37,11 +37,11 @@ - * auth info. - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *c = NULL; - CURLM *m = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int running; - - start_test_timing(); -@@ -53,7 +53,8 @@ int test(char *URL) - easy_setopt(c, CURLOPT_PROXY, libtest_arg2); /* set in first.c */ - easy_setopt(c, CURLOPT_URL, URL); - easy_setopt(c, CURLOPT_USERPWD, "test:ing"); -- easy_setopt(c, CURLOPT_PROXYUSERPWD, "test:ing"); -+ easy_setopt(c, CURLOPT_PROXYUSERNAME, "test%20"); -+ easy_setopt(c, CURLOPT_PROXYPASSWORD, "ing%41"); - easy_setopt(c, CURLOPT_HTTPPROXYTUNNEL, 1L); - easy_setopt(c, CURLOPT_HEADER, 1L); - easy_setopt(c, CURLOPT_VERBOSE, 1L); -diff --git a/tests/libtest/lib504.c b/tests/libtest/lib504.c -index cbe1d5773..a9f96c8dd 100644 ---- a/tests/libtest/lib504.c -+++ b/tests/libtest/lib504.c -@@ -36,10 +36,10 @@ - * Use multi interface to get document over proxy with bad port number. - * This caused the interface to "hang" in libcurl 7.10.2. - */ --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *c = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - CURLM *m = NULL; - fd_set rd, wr, exc; - int running; -@@ -72,6 +72,21 @@ int test(char *URL) - - multi_perform(m, &running); - -+ while(running) { -+ CURLMcode mres; -+ int num; -+ mres = curl_multi_wait(m, NULL, 0, TEST_HANG_TIMEOUT, &num); -+ if(mres != CURLM_OK) { -+ printf("curl_multi_wait() returned %d\n", mres); -+ res = TEST_ERR_MAJOR_BAD; -+ goto test_cleanup; -+ } -+ -+ abort_on_test_timeout(); -+ multi_perform(m, &running); -+ abort_on_test_timeout(); -+ } -+ - abort_on_test_timeout(); - - if(!running) { -diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c -index 6c67ed901..de383232c 100644 ---- a/tests/libtest/lib505.c -+++ b/tests/libtest/lib505.c -@@ -36,7 +36,7 @@ - * Example based on source code provided by Erick Nuwendam. Thanks! - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib506.c b/tests/libtest/lib506.c -index dd4759ac4..03eb11ddd 100644 ---- a/tests/libtest/lib506.c -+++ b/tests/libtest/lib506.c -@@ -42,8 +42,8 @@ struct userdata { - static int locks[3]; - - /* lock callback */ --static void my_lock(CURL *handle, curl_lock_data data, -- curl_lock_access laccess, void *useptr) -+static void test_lock(CURL *handle, curl_lock_data data, -+ curl_lock_access laccess, void *useptr) - { - const char *what; - struct userdata *user = (struct userdata *)useptr; -@@ -82,7 +82,7 @@ static void my_lock(CURL *handle, curl_lock_data data, - } - - /* unlock callback */ --static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) -+static void test_unlock(CURL *handle, curl_lock_data data, void *useptr) - { - const char *what; - struct userdata *user = (struct userdata *)useptr; -@@ -127,7 +127,7 @@ static struct curl_slist *sethost(struct curl_slist *headers) - - - /* the dummy thread function */ --static void *fire(void *ptr) -+static void *test_fire(void *ptr) - { - CURLcode code; - struct curl_slist *headers; -@@ -172,9 +172,9 @@ static char *suburl(const char *base, int i) - - - /* test function */ --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURLSHcode scode = CURLSHE_OK; - CURLcode code = CURLE_OK; - char *url = NULL; -@@ -207,11 +207,11 @@ int test(char *URL) - - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_LOCKFUNC\n"); -- scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); -+ scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock); - } - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_UNLOCKFUNC\n"); -- scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); -+ scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock); - } - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_USERDATA\n"); -@@ -261,7 +261,7 @@ int test(char *URL) - curl_easy_cleanup(curl); - - -- res = 0; -+ res = CURLE_OK; - - /* start treads */ - for(i = 1; i <= THREADS; i++) { -@@ -272,13 +272,13 @@ int test(char *URL) - - /* simulate thread, direct call of "thread" function */ - printf("*** run %d\n",i); -- fire(&tdata); -+ test_fire(&tdata); - - curl_free(tdata.url); - } - - -- /* fetch a another one and save cookies */ -+ /* fetch another one and save cookies */ - printf("*** run %d\n", i); - curl = curl_easy_init(); - if(!curl) { -diff --git a/tests/libtest/lib507.c b/tests/libtest/lib507.c -index be6dd7eee..a228d08aa 100644 ---- a/tests/libtest/lib507.c -+++ b/tests/libtest/lib507.c -@@ -29,13 +29,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; - CURLM *multi = NULL; - int still_running; -- int i = -1; -- int res = 0; -+ CURLcode i = (CURLcode)-1; -+ CURLcode res = CURLE_OK; - CURLMsg *msg; - - start_test_timing(); -diff --git a/tests/libtest/lib508.c b/tests/libtest/lib508.c -index b793731b3..fc25a0df6 100644 ---- a/tests/libtest/lib508.c -+++ b/tests/libtest/lib508.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]="this is what we post to the silly web server\n"; -+static char testdata[]="this is what we post to the silly web server\n"; - - struct WriteThis { - char *readptr; -@@ -49,15 +49,15 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; - - struct WriteThis pooh; - -- pooh.readptr = data; -- pooh.sizeleft = strlen(data); -+ pooh.readptr = testdata; -+ pooh.sizeleft = strlen(testdata); - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); -diff --git a/tests/libtest/lib509.c b/tests/libtest/lib509.c -index cb510ef21..8a03b3b19 100644 ---- a/tests/libtest/lib509.c -+++ b/tests/libtest/lib509.c -@@ -69,7 +69,7 @@ static void custom_free(void *ptr) - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - unsigned char a[] = {0x2f, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7}; -@@ -113,5 +113,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib510.c b/tests/libtest/lib510.c -index 87a85a557..2abd1cb7e 100644 ---- a/tests/libtest/lib510.c -+++ b/tests/libtest/lib510.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static const char *post[]={ -+static const char * const testpost[]={ - "one", - "two", - "three", -@@ -46,7 +46,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - if(size*nmemb < 1) - return 0; - -- data = post[pooh->counter]; -+ data = testpost[pooh->counter]; - - if(data) { - size_t len = strlen(data); -@@ -61,7 +61,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib511.c b/tests/libtest/lib511.c -index c53224801..b357e4d68 100644 ---- a/tests/libtest/lib511.c -+++ b/tests/libtest/lib511.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -54,5 +54,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib512.c b/tests/libtest/lib512.c -index 706acb2e1..02e0d487c 100644 ---- a/tests/libtest/lib512.c -+++ b/tests/libtest/lib512.c -@@ -28,7 +28,7 @@ - /* Test case code based on source in a bug report filed by James Bursa on - 28 Apr 2004 */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode code; - int rc = 99; -@@ -72,5 +72,5 @@ int test(char *URL) - else - rc = 5; - -- return rc; -+ return (CURLcode)rc; - } -diff --git a/tests/libtest/lib513.c b/tests/libtest/lib513.c -index b381098fb..208245acf 100644 ---- a/tests/libtest/lib513.c -+++ b/tests/libtest/lib513.c -@@ -34,7 +34,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return CURL_READFUNC_ABORT; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -81,5 +81,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib514.c b/tests/libtest/lib514.c -index 0f31c8c4c..738770613 100644 ---- a/tests/libtest/lib514.c -+++ b/tests/libtest/lib514.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -77,5 +77,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib515.c b/tests/libtest/lib515.c -index 3c744fb95..7edfe4e5e 100644 ---- a/tests/libtest/lib515.c -+++ b/tests/libtest/lib515.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -58,5 +58,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib516.c b/tests/libtest/lib516.c -index 59abb091a..fc94eaabc 100644 ---- a/tests/libtest/lib516.c -+++ b/tests/libtest/lib516.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -59,5 +59,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib517.c b/tests/libtest/lib517.c -index 0d1ea2eb4..e769ae5af 100644 ---- a/tests/libtest/lib517.c -+++ b/tests/libtest/lib517.c -@@ -153,7 +153,7 @@ static const struct dcheck dates[] = { - { NULL, 0 } - }; - --int test(char *URL) -+CURLcode test(char *URL) - { - int i; - int error = 0; -@@ -169,5 +169,5 @@ int test(char *URL) - } - } - -- return error; -+ return error == 0 ? CURLE_OK : TEST_ERR_FAILURE; - } -diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c -index 28a50b22a..289692c3f 100644 ---- a/tests/libtest/lib518.c -+++ b/tests/libtest/lib518.c -@@ -50,7 +50,7 @@ - - #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) - --static int *fd = NULL; -+static int *testfd = NULL; - static struct rlimit num_open; - static char msgbuff[256]; - -@@ -68,10 +68,10 @@ static void close_file_descriptors(void) - for(num_open.rlim_cur = 0; - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) -- if(fd[num_open.rlim_cur] > 0) -- close(fd[num_open.rlim_cur]); -- free(fd); -- fd = NULL; -+ if(testfd[num_open.rlim_cur] > 0) -+ close(testfd[num_open.rlim_cur]); -+ free(testfd); -+ testfd = NULL; - } - - static int fopen_works(void) -@@ -120,7 +120,7 @@ static void rlim2str(char *buf, size_t len, rlim_t val) - } - } - --static int rlimit(int keep_open) -+static int test_rlimit(int keep_open) - { - rlim_t nitems, i; - int *memchunk = NULL; -@@ -239,7 +239,7 @@ static int rlimit(int keep_open) - * avoid a low memory condition once the file descriptors are - * open. System conditions that could make the test fail should - * be addressed in the precheck phase. This chunk of memory shall -- * be always free()ed before exiting the rlimit() function so -+ * be always free()ed before exiting the test_rlimit() function so - * that it becomes available to the test. - */ - -@@ -276,7 +276,7 @@ static int rlimit(int keep_open) - - /* verify that we won't overflow size_t in malloc() */ - -- if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) { -+ if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*testfd)) { - rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_max); - msnprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " - "file descriptors, would overflow size_t", strbuff1); -@@ -291,9 +291,9 @@ static int rlimit(int keep_open) - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); - -- fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); -- if(!fd) { -- store_errmsg("fd, malloc() failed", errno); -+ testfd = malloc(sizeof(*testfd) * (size_t)(num_open.rlim_max)); -+ if(!testfd) { -+ store_errmsg("testfd, malloc() failed", errno); - fprintf(stderr, "%s\n", msgbuff); - free(memchunk); - return -7; -@@ -301,25 +301,25 @@ static int rlimit(int keep_open) - - /* initialize it to fight lazy allocation */ - -- fprintf(stderr, "initializing fd array\n"); -+ fprintf(stderr, "initializing testfd array\n"); - - for(num_open.rlim_cur = 0; - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) -- fd[num_open.rlim_cur] = -1; -+ testfd[num_open.rlim_cur] = -1; - - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "trying to open %s file descriptors\n", strbuff); - - /* open a dummy descriptor */ - -- fd[0] = open(DEV_NULL, O_RDONLY); -- if(fd[0] < 0) { -+ testfd[0] = open(DEV_NULL, O_RDONLY); -+ if(testfd[0] < 0) { - msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); - store_errmsg(strbuff, errno); - fprintf(stderr, "%s\n", msgbuff); -- free(fd); -- fd = NULL; -+ free(testfd); -+ testfd = NULL; - free(memchunk); - return -8; - } -@@ -330,11 +330,11 @@ static int rlimit(int keep_open) - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) { - -- fd[num_open.rlim_cur] = dup(fd[0]); -+ testfd[num_open.rlim_cur] = dup(testfd[0]); - -- if(fd[num_open.rlim_cur] < 0) { -+ if(testfd[num_open.rlim_cur] < 0) { - -- fd[num_open.rlim_cur] = -1; -+ testfd[num_open.rlim_cur] = -1; - - rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); - msnprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); -@@ -355,11 +355,11 @@ static int rlimit(int keep_open) - fprintf(stderr, "%s\n", msgbuff); - - for(num_open.rlim_cur = 0; -- fd[num_open.rlim_cur] >= 0; -+ testfd[num_open.rlim_cur] >= 0; - num_open.rlim_cur++) -- close(fd[num_open.rlim_cur]); -- free(fd); -- fd = NULL; -+ close(testfd[num_open.rlim_cur]); -+ free(testfd); -+ testfd = NULL; - free(memchunk); - return -9; - } -@@ -368,7 +368,7 @@ static int rlimit(int keep_open) - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "%s file descriptors open\n", strbuff); - --#if !defined(HAVE_POLL_FINE) && !defined(USE_WINSOCK) -+#if !defined(HAVE_POLL) && !defined(USE_WINSOCK) - - /* - * when using select() instead of poll() we cannot test -@@ -396,8 +396,8 @@ static int rlimit(int keep_open) - for(rl.rlim_cur = 0; - rl.rlim_cur < num_open.rlim_max; - rl.rlim_cur++) { -- if((fd[rl.rlim_cur] > 0) && -- ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) { -+ if((testfd[rl.rlim_cur] > 0) && -+ ((unsigned int)testfd[rl.rlim_cur] > num_open.rlim_cur)) { - msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", - FD_SETSIZE); - store_errmsg(strbuff, 0); -@@ -445,21 +445,21 @@ static int rlimit(int keep_open) - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; - - if(!strcmp(URL, "check")) { - /* used by the test script to ask if we can run this test or not */ -- if(rlimit(FALSE)) { -- fprintf(stdout, "rlimit problem: %s\n", msgbuff); -- return 1; -+ if(test_rlimit(FALSE)) { -+ fprintf(stdout, "test_rlimit problem: %s\n", msgbuff); -+ return (CURLcode)1; - } -- return 0; /* sure, run this! */ -+ return CURLE_OK; /* sure, run this! */ - } - -- if(rlimit(TRUE)) { -+ if(test_rlimit(TRUE)) { - /* failure */ - return TEST_ERR_MAJOR_BAD; - } -@@ -492,12 +492,12 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } - - #else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ - --int test(char *URL) -+CURLcode test(char *URL) - { - (void)URL; - printf("system lacks necessary system function(s)"); -diff --git a/tests/libtest/lib519.c b/tests/libtest/lib519.c -index bf950bd45..fcc8a6a04 100644 ---- a/tests/libtest/lib519.c -+++ b/tests/libtest/lib519.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -62,5 +62,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib520.c b/tests/libtest/lib520.c -index 7e5d0abd7..13257c470 100644 ---- a/tests/libtest/lib520.c -+++ b/tests/libtest/lib520.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -53,5 +53,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib521.c b/tests/libtest/lib521.c -index e3611685b..dc8844375 100644 ---- a/tests/libtest/lib521.c -+++ b/tests/libtest/lib521.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -54,5 +54,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib523.c b/tests/libtest/lib523.c -index 86128e6c0..5c7338e7c 100644 ---- a/tests/libtest/lib523.c -+++ b/tests/libtest/lib523.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -55,5 +55,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib524.c b/tests/libtest/lib524.c -index 6b8cc207d..ec721bee2 100644 ---- a/tests/libtest/lib524.c -+++ b/tests/libtest/lib524.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -53,5 +53,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c -index 3f8abeef1..f64070b56 100644 ---- a/tests/libtest/lib525.c -+++ b/tests/libtest/lib525.c -@@ -31,9 +31,9 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - FILE *hd_src = NULL; - int hd; -diff --git a/tests/libtest/lib526.c b/tests/libtest/lib526.c -index 12b65c023..5fd81b51e 100644 ---- a/tests/libtest/lib526.c -+++ b/tests/libtest/lib526.c -@@ -52,9 +52,9 @@ - - #define NUM_HANDLES 4 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl[NUM_HANDLES]; - int running; - CURLM *m = NULL; -@@ -163,7 +163,7 @@ test_cleanup: - cleanup'ed yet, in this case we have to cleanup them or otherwise these - will be leaked, let's use undocumented cleanup sequence - type UB */ - -- if(res) -+ if(res != CURLE_OK) - for(i = 0; i < NUM_HANDLES; i++) - curl_easy_cleanup(curl[i]); - -diff --git a/tests/libtest/lib530.c b/tests/libtest/lib530.c -index 0173dd978..5f24c904b 100644 ---- a/tests/libtest/lib530.c -+++ b/tests/libtest/lib530.c -@@ -38,15 +38,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --struct Sockets --{ -+struct Sockets { - curl_socket_t *sockets; - int count; /* number of sockets actually stored in array */ - int max_count; /* max number of sockets that fit in allocated array */ - }; - --struct ReadWriteSockets --{ -+struct ReadWriteSockets { - struct Sockets read, write; - }; - -@@ -191,7 +189,7 @@ static int checkForCompletion(CURLM *curl, int *success) - } - else { - fprintf(stderr, "Got an unexpected message from curl: %i\n", -- (int)message->msg); -+ message->msg); - result = 1; - *success = 0; - } -@@ -228,7 +226,7 @@ static void updateFdSet(struct Sockets *sockets, fd_set* fdset, - } - - static int socket_action(CURLM *curl, curl_socket_t s, int evBitmask, -- const char *info) -+ const char *info) - { - int numhandles = 0; - CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles); -@@ -258,9 +256,9 @@ static int checkFdSet(CURLM *curl, - return result; - } - --static int testone(char *URL, int timercb, int socketcb) -+static CURLcode testone(char *URL, int timercb, int socketcb) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; CURLM *m = NULL; - struct ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}}; - struct timeval timeout = {-1, 0}; -@@ -276,7 +274,7 @@ static int testone(char *URL, int timercb, int socketcb) - start_test_timing(); - - res_global_init(CURL_GLOBAL_ALL); -- if(res) -+ if(res != CURLE_OK) - return res; - - easy_init(curl); -@@ -297,9 +295,10 @@ static int testone(char *URL, int timercb, int socketcb) - - multi_add_handle(m, curl); - -- res = socket_action(m, CURL_SOCKET_TIMEOUT, 0, "timeout"); -- if(res) -+ if(socket_action(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) { -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; -+ } - - while(!checkForCompletion(m, &success)) { - fd_set readSet, writeSet; -@@ -325,18 +324,21 @@ static int testone(char *URL, int timercb, int socketcb) - select_test((int)maxFd, &readSet, &writeSet, NULL, &tv); - - /* Check the sockets for reading / writing */ -- res = checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read"); -- if(res) -+ if(checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN, "read")) { -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; -- res = checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write"); -- if(res) -+ } -+ if(checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT, "write")) { -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; -+ } - - if(timeout.tv_sec != -1 && getMicroSecondTimeout(&timeout) == 0) { - /* Curl's timer has elapsed. */ -- res = socket_action(m, CURL_SOCKET_TIMEOUT, 0, "timeout"); -- if(res) -+ if(socket_action(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) { -+ res = TEST_ERR_BAD_TIMEOUT; - goto test_cleanup; -+ } - } - - abort_on_test_timeout(); -@@ -362,9 +364,9 @@ test_cleanup: - return res; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int rc; -+ CURLcode rc; - /* rerun the same transfer multiple times and make it fail in different - callback calls */ - rc = testone(URL, 0, 0); -@@ -387,5 +389,5 @@ int test(char *URL) - if(!rc) - fprintf(stderr, "test 0/2 failed: %d\n", rc); - -- return 0; -+ return CURLE_OK; - } -diff --git a/tests/libtest/lib533.c b/tests/libtest/lib533.c -index 0f6a89c2f..dc48bb462 100644 ---- a/tests/libtest/lib533.c -+++ b/tests/libtest/lib533.c -@@ -33,9 +33,9 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - int running; - CURLM *m = NULL; -diff --git a/tests/libtest/lib536.c b/tests/libtest/lib536.c -index 7e53e2255..73edf43d4 100644 ---- a/tests/libtest/lib536.c -+++ b/tests/libtest/lib536.c -@@ -37,7 +37,7 @@ static void proxystat(CURL *curl) - } - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURL *curl; -@@ -80,5 +80,5 @@ test_cleanup: - curl_slist_free_all(host); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c -index c35aea1b4..6e1baee7e 100644 ---- a/tests/libtest/lib537.c -+++ b/tests/libtest/lib537.c -@@ -34,9 +34,7 @@ - #include "warnless.h" - #include "memdebug.h" - --#if !defined(HAVE_POLL_FINE) && \ -- !defined(USE_WINSOCK) && \ -- !defined(FD_SETSIZE) -+#if !defined(HAVE_POLL) && !defined(USE_WINSOCK) && !defined(FD_SETSIZE) - #error "this test requires FD_SETSIZE" - #endif - -@@ -50,7 +48,7 @@ - - #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) - --static int *fd = NULL; -+static int *testfd = NULL; - static struct rlimit num_open; - static char msgbuff[256]; - -@@ -68,10 +66,10 @@ static void close_file_descriptors(void) - for(num_open.rlim_cur = 0; - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) -- if(fd[num_open.rlim_cur] > 0) -- close(fd[num_open.rlim_cur]); -- free(fd); -- fd = NULL; -+ if(testfd[num_open.rlim_cur] > 0) -+ close(testfd[num_open.rlim_cur]); -+ free(testfd); -+ testfd = NULL; - } - - static int fopen_works(void) -@@ -120,7 +118,7 @@ static void rlim2str(char *buf, size_t len, rlim_t val) - } - } - --static int rlimit(int keep_open) -+static int test_rlimit(int keep_open) - { - int *tmpfd; - rlim_t nitems, i; -@@ -145,6 +143,15 @@ static int rlimit(int keep_open) - rlim2str(strbuff, sizeof(strbuff), rl.rlim_max); - fprintf(stderr, "initial hard limit: %s\n", strbuff); - -+ /* If the OS allows a HUGE number of open files, we do not run. -+ * Modern debian sid reports a limit of 134217724 and this tests -+ * takes minutes. */ -+#define LIMIT_CAP (256*1024) -+ if(rl.rlim_cur > LIMIT_CAP) { -+ fprintf(stderr, "soft limit above %ld, not running\n", (long)LIMIT_CAP); -+ return -2; -+ } -+ - /* - * if soft limit and hard limit are different we ask the - * system to raise soft limit all the way up to the hard -@@ -212,7 +219,7 @@ static int rlimit(int keep_open) - * avoid a low memory condition once the file descriptors are - * open. System conditions that could make the test fail should - * be addressed in the precheck phase. This chunk of memory shall -- * be always free()ed before exiting the rlimit() function so -+ * be always free()ed before exiting the test_rlimit() function so - * that it becomes available to the test. - */ - -@@ -264,7 +271,7 @@ static int rlimit(int keep_open) - - /* verify that we won't overflow size_t in malloc() */ - -- if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) { -+ if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*testfd)) { - rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_max); - msnprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " - "file descriptors, would overflow size_t", strbuff1); -@@ -280,14 +287,14 @@ static int rlimit(int keep_open) - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); - -- fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); -- if(!fd) { -- fprintf(stderr, "fd, malloc() failed\n"); -+ testfd = malloc(sizeof(*testfd) * (size_t)(num_open.rlim_max)); -+ if(!testfd) { -+ fprintf(stderr, "testfd, malloc() failed\n"); - num_open.rlim_max /= 2; - } -- } while(num_open.rlim_max && !fd); -- if(!fd) { -- store_errmsg("fd, malloc() failed", errno); -+ } while(num_open.rlim_max && !testfd); -+ if(!testfd) { -+ store_errmsg("testfd, malloc() failed", errno); - fprintf(stderr, "%s\n", msgbuff); - free(memchunk); - return -6; -@@ -295,25 +302,25 @@ static int rlimit(int keep_open) - - /* initialize it to fight lazy allocation */ - -- fprintf(stderr, "initializing fd array\n"); -+ fprintf(stderr, "initializing testfd array\n"); - - for(num_open.rlim_cur = 0; - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) -- fd[num_open.rlim_cur] = -1; -+ testfd[num_open.rlim_cur] = -1; - - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "trying to open %s file descriptors\n", strbuff); - - /* open a dummy descriptor */ - -- fd[0] = open(DEV_NULL, O_RDONLY); -- if(fd[0] < 0) { -+ testfd[0] = open(DEV_NULL, O_RDONLY); -+ if(testfd[0] < 0) { - msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); - store_errmsg(strbuff, errno); - fprintf(stderr, "%s\n", msgbuff); -- free(fd); -- fd = NULL; -+ free(testfd); -+ testfd = NULL; - free(memchunk); - return -7; - } -@@ -324,11 +331,11 @@ static int rlimit(int keep_open) - num_open.rlim_cur < num_open.rlim_max; - num_open.rlim_cur++) { - -- fd[num_open.rlim_cur] = dup(fd[0]); -+ testfd[num_open.rlim_cur] = dup(testfd[0]); - -- if(fd[num_open.rlim_cur] < 0) { -+ if(testfd[num_open.rlim_cur] < 0) { - -- fd[num_open.rlim_cur] = -1; -+ testfd[num_open.rlim_cur] = -1; - - rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); - msnprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); -@@ -348,10 +355,10 @@ static int rlimit(int keep_open) - fprintf(stderr, "%s\n", strbuff); - - for(num_open.rlim_cur = num_open.rlim_max; -- fd[num_open.rlim_cur] >= 0; -+ testfd[num_open.rlim_cur] >= 0; - num_open.rlim_cur++) { -- close(fd[num_open.rlim_cur]); -- fd[num_open.rlim_cur] = -1; -+ close(testfd[num_open.rlim_cur]); -+ testfd[num_open.rlim_cur] = -1; - } - - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); -@@ -359,9 +366,9 @@ static int rlimit(int keep_open) - - /* we don't care if we can't shrink it */ - -- tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max)); -+ tmpfd = realloc(testfd, sizeof(*testfd) * (size_t)(num_open.rlim_max)); - if(tmpfd) { -- fd = tmpfd; -+ testfd = tmpfd; - tmpfd = NULL; - } - -@@ -372,7 +379,7 @@ static int rlimit(int keep_open) - rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); - fprintf(stderr, "%s file descriptors open\n", strbuff); - --#if !defined(HAVE_POLL_FINE) && !defined(USE_WINSOCK) -+#if !defined(HAVE_POLL) && !defined(USE_WINSOCK) - - /* - * when using select() instead of poll() we cannot test -@@ -400,8 +407,8 @@ static int rlimit(int keep_open) - for(rl.rlim_cur = 0; - rl.rlim_cur < num_open.rlim_max; - rl.rlim_cur++) { -- if((fd[rl.rlim_cur] > 0) && -- ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) { -+ if((testfd[rl.rlim_cur] > 0) && -+ ((unsigned int)testfd[rl.rlim_cur] > num_open.rlim_cur)) { - msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", - FD_SETSIZE); - store_errmsg(strbuff, 0); -@@ -449,21 +456,21 @@ static int rlimit(int keep_open) - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; - - if(!strcmp(URL, "check")) { - /* used by the test script to ask if we can run this test or not */ -- if(rlimit(FALSE)) { -- fprintf(stdout, "rlimit problem: %s\n", msgbuff); -- return 1; -+ if(test_rlimit(FALSE)) { -+ fprintf(stdout, "test_rlimit problem: %s\n", msgbuff); -+ return (CURLcode)1; - } -- return 0; /* sure, run this! */ -+ return CURLE_OK; /* sure, run this! */ - } - -- if(rlimit(TRUE)) { -+ if(test_rlimit(TRUE)) { - /* failure */ - return TEST_ERR_MAJOR_BAD; - } -@@ -496,16 +503,16 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } - - #else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ - --int test(char *URL) -+CURLcode test(char *URL) - { - (void)URL; - printf("system lacks necessary system function(s)"); -- return 1; /* skip test */ -+ return (CURLcode)1; /* skip test */ - } - - #endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ -diff --git a/tests/libtest/lib539.c b/tests/libtest/lib539.c -index 75f146c00..2e079fae3 100644 ---- a/tests/libtest/lib539.c -+++ b/tests/libtest/lib539.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -55,18 +55,11 @@ int test(char *URL) - - /* - * Change the FTP_FILEMETHOD option to use full paths rather than a CWD -- * command. Alter the URL's path a bit, appending a "./". Use an innocuous -- * QUOTE command, after which curl will CWD to ftp_conn->entrypath and then -- * (on the next call to ftp_statemach_act) find a non-zero ftpconn->dirdepth -- * even though no directories are stored in the ftpconn->dirs array (after a -- * call to freedirs). -+ * command. Use an innocuous QUOTE command, after which curl will CWD to -+ * ftp_conn->entrypath and then (on the next call to ftp_statemach_act) -+ * find a non-zero ftpconn->dirdepth even though no directories are stored -+ * in the ftpconn->dirs array (after a call to freedirs). - */ -- newURL = aprintf("%s./", URL); -- if(!newURL) { -- curl_easy_cleanup(curl); -- curl_global_cleanup(); -- return TEST_ERR_MAJOR_BAD; -- } - - slist = curl_slist_append(NULL, "SYST"); - if(!slist) { -@@ -76,7 +69,7 @@ int test(char *URL) - return TEST_ERR_MAJOR_BAD; - } - -- test_setopt(curl, CURLOPT_URL, newURL); -+ test_setopt(curl, CURLOPT_URL, libtest_arg2); - test_setopt(curl, CURLOPT_FTP_FILEMETHOD, (long) CURLFTPMETHOD_NOCWD); - test_setopt(curl, CURLOPT_QUOTE, slist); - -@@ -89,5 +82,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib540.c b/tests/libtest/lib540.c -index ab9fef9b4..b53b95563 100644 ---- a/tests/libtest/lib540.c -+++ b/tests/libtest/lib540.c -@@ -46,68 +46,68 @@ - - #define NUM_HANDLES 2 - --static CURL *eh[NUM_HANDLES]; -+static CURL *testeh[NUM_HANDLES]; - --static int init(int num, CURLM *cm, const char *url, const char *userpwd, -- struct curl_slist *headers) -+static CURLcode init(int num, CURLM *cm, const char *url, const char *userpwd, -+ struct curl_slist *headers) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - -- res_easy_init(eh[num]); -+ res_easy_init(testeh[num]); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_URL, url); -+ res_easy_setopt(testeh[num], CURLOPT_URL, url); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_PROXY, PROXY); -+ res_easy_setopt(testeh[num], CURLOPT_PROXY, PROXY); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_PROXYUSERPWD, userpwd); -+ res_easy_setopt(testeh[num], CURLOPT_PROXYUSERPWD, userpwd); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); -+ res_easy_setopt(testeh[num], CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_VERBOSE, 1L); -+ res_easy_setopt(testeh[num], CURLOPT_VERBOSE, 1L); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_HEADER, 1L); -+ res_easy_setopt(testeh[num], CURLOPT_HEADER, 1L); - if(res) - goto init_failed; - -- res_easy_setopt(eh[num], CURLOPT_HTTPHEADER, headers); /* custom Host: */ -+ res_easy_setopt(testeh[num], CURLOPT_HTTPHEADER, headers); /* custom Host: */ - if(res) - goto init_failed; - -- res_multi_add_handle(cm, eh[num]); -+ res_multi_add_handle(cm, testeh[num]); - if(res) - goto init_failed; - -- return 0; /* success */ -+ return CURLE_OK; /* success */ - - init_failed: - -- curl_easy_cleanup(eh[num]); -- eh[num] = NULL; -+ curl_easy_cleanup(testeh[num]); -+ testeh[num] = NULL; - - return res; /* failure */ - } - --static int loop(int num, CURLM *cm, const char *url, const char *userpwd, -- struct curl_slist *headers) -+static CURLcode loop(int num, CURLM *cm, const char *url, const char *userpwd, -+ struct curl_slist *headers) - { - CURLMsg *msg; - long L; - int Q, U = -1; - fd_set R, W, E; - struct timeval T; -- int res = 0; -+ CURLcode res = CURLE_OK; - - res = init(num, cm, url, userpwd, headers); - if(res) -@@ -174,8 +174,8 @@ static int loop(int num, CURLM *cm, const char *url, const char *userpwd, - curl_multi_remove_handle(cm, e); - curl_easy_cleanup(e); - for(i = 0; i < NUM_HANDLES; i++) { -- if(eh[i] == e) { -- eh[i] = NULL; -+ if(testeh[i] == e) { -+ testeh[i] = NULL; - break; - } - } -@@ -189,24 +189,24 @@ static int loop(int num, CURLM *cm, const char *url, const char *userpwd, - return res; - } - -- return 0; /* success */ -+ return CURLE_OK; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *cm = NULL; - struct curl_slist *headers = NULL; - char buffer[246]; /* naively fixed-size */ -- int res = 0; -+ CURLcode res = CURLE_OK; - int i; - - for(i = 0; i < NUM_HANDLES; i++) -- eh[i] = NULL; -+ testeh[i] = NULL; - - start_test_timing(); - - if(test_argc < 4) -- return 99; -+ return (CURLcode)99; - - msnprintf(buffer, sizeof(buffer), "Host: %s", HOST); - -@@ -243,8 +243,8 @@ test_cleanup: - /* proper cleanup sequence - type PB */ - - for(i = 0; i < NUM_HANDLES; i++) { -- curl_multi_remove_handle(cm, eh[i]); -- curl_easy_cleanup(eh[i]); -+ curl_multi_remove_handle(cm, testeh[i]); -+ curl_easy_cleanup(testeh[i]); - } - - curl_multi_cleanup(cm); -diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c -index 75c74fbff..7dd53195e 100644 ---- a/tests/libtest/lib541.c -+++ b/tests/libtest/lib541.c -@@ -33,7 +33,7 @@ - * Two FTP uploads, the second with no content sent. - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -51,7 +51,7 @@ int test(char *URL) - fprintf(stderr, "fopen failed with error: %d %s\n", - errno, strerror(errno)); - fprintf(stderr, "Error opening file: %s\n", libtest_arg2); -- return -2; /* if this happens things are major weird */ -+ return (CURLcode)-2; /* if this happens things are major weird */ - } - - /* get the file size of the local file */ -diff --git a/tests/libtest/lib542.c b/tests/libtest/lib542.c -index 27429fd6c..2be67488e 100644 ---- a/tests/libtest/lib542.c -+++ b/tests/libtest/lib542.c -@@ -33,7 +33,7 @@ - * FTP get with NOBODY but no HEADER - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib543.c b/tests/libtest/lib543.c -index 2bec2f1a6..077cf16b6 100644 ---- a/tests/libtest/lib543.c -+++ b/tests/libtest/lib543.c -@@ -27,7 +27,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - static const unsigned char a[] = { - 0x9c, 0x26, 0x4b, 0x3d, 0x49, 0x4, 0xa1, 0x1, -@@ -68,5 +68,5 @@ int test(char *URL) - } - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib544.c b/tests/libtest/lib544.c -index a58fa05e3..6228e7d9f 100644 ---- a/tests/libtest/lib544.c -+++ b/tests/libtest/lib544.c -@@ -31,7 +31,7 @@ static char teststring[] = - 'w', 'i', 't', 'h', ' ', 'a', 'n', ' ', - 'e', 'm', 'b', 'e', 'd', 'd', 'e', 'd', ' ', 'N', 'U', 'L'}; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -80,5 +80,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib547.c b/tests/libtest/lib547.c -index e65f33b78..a84ce999c 100644 ---- a/tests/libtest/lib547.c -+++ b/tests/libtest/lib547.c -@@ -72,7 +72,7 @@ static curlioerr ioctlcallback(CURL *handle, - - #endif - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -123,5 +123,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib549.c b/tests/libtest/lib549.c -index 8e91d9356..7bd67093f 100644 ---- a/tests/libtest/lib549.c -+++ b/tests/libtest/lib549.c -@@ -30,7 +30,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -52,7 +52,7 @@ int test(char *URL) - test_setopt(curl, CURLOPT_PROXY_TRANSFER_MODE, 1L); - test_setopt(curl, CURLOPT_VERBOSE, 1L); - if(libtest_arg3) { -- /* enable ascii/text mode */ -+ /* enable ASCII/text mode */ - test_setopt(curl, CURLOPT_TRANSFERTEXT, 1L); - } - -@@ -63,5 +63,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib552.c b/tests/libtest/lib552.c -index 436b86ec0..0920b025a 100644 ---- a/tests/libtest/lib552.c -+++ b/tests/libtest/lib552.c -@@ -30,7 +30,7 @@ - #include "warnless.h" - #include "memdebug.h" - --struct data { -+struct testdata { - char trace_ascii; /* 1 or 0 */ - }; - -@@ -50,7 +50,7 @@ void dump(const char *text, - - fprintf(stream, "%s, %zu bytes (0x%zx)\n", text, size, size); - -- for(i = 0; i= 0x20) && (ptr[i + c]<0x80)? ptr[i + c] : '.'); -+ (ptr[i + c] >= 0x20) && (ptr[i + c] < 0x80) ? ptr[i + c] : '.'); - /* check again for 0D0A, to avoid an extra \n if it's at width */ - if(nohex && (i + c + 2 < size) && ptr[i + c + 1] == 0x0D && - ptr[i + c + 2] == 0x0A) { -@@ -89,7 +89,7 @@ int my_trace(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) - { -- struct data *config = (struct data *)userp; -+ struct testdata *config = (struct testdata *)userp; - const char *text; - (void)handle; /* prevent compiler warning */ - -@@ -141,7 +141,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *stream) - } - - --static size_t write_callback(void *ptr, size_t size, size_t nmemb, -+static size_t write_callback(char *ptr, size_t size, size_t nmemb, - void *stream) - { - int amount = curlx_uztosi(size * nmemb); -@@ -166,15 +166,15 @@ static curlioerr ioctl_callback(CURL *handle, int cmd, void *clientp) - - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -- struct data config; -+ struct testdata config; - size_t i; - static const char fill[] = "test data"; - -- config.trace_ascii = 1; /* enable ascii tracing */ -+ config.trace_ascii = 1; /* enable ASCII tracing */ - - global_init(CURL_GLOBAL_ALL); - easy_init(curl); -@@ -217,5 +217,5 @@ test_cleanup: - - curl_easy_cleanup(curl); - curl_global_cleanup(); -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib553.c b/tests/libtest/lib553.c -index f282c8950..e33cf148f 100644 ---- a/tests/libtest/lib553.c -+++ b/tests/libtest/lib553.c -@@ -55,9 +55,9 @@ static size_t myreadfunc(char *ptr, size_t size, size_t nmemb, void *stream) - #define NUM_HEADERS 8 - #define SIZE_HEADERS 5000 - --static char buf[SIZE_HEADERS + 100]; -+static char testbuf[SIZE_HEADERS + 100]; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_FAILED_INIT; -@@ -77,10 +77,10 @@ int test(char *URL) - } - - for(i = 0; i < NUM_HEADERS; i++) { -- int len = msnprintf(buf, sizeof(buf), "Header%d: ", i); -- memset(&buf[len], 'A', SIZE_HEADERS); -- buf[len + SIZE_HEADERS] = 0; /* null-terminate */ -- hl = curl_slist_append(headerlist, buf); -+ int len = msnprintf(testbuf, sizeof(testbuf), "Header%d: ", i); -+ memset(&testbuf[len], 'A', SIZE_HEADERS); -+ testbuf[len + SIZE_HEADERS] = 0; /* null-terminate */ -+ hl = curl_slist_append(headerlist, testbuf); - if(!hl) - goto test_cleanup; - headerlist = hl; -@@ -109,5 +109,5 @@ test_cleanup: - - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib554.c b/tests/libtest/lib554.c -index 1d049815c..10c19a380 100644 ---- a/tests/libtest/lib554.c -+++ b/tests/libtest/lib554.c -@@ -21,12 +21,11 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ --#define CURL_DISABLE_DEPRECATION /* Using and testing the form api */ - #include "test.h" - - #include "memdebug.h" - --static char data[]= -+static char testdata[]= - "this is what we post to the silly web server\n"; - - struct WriteThis { -@@ -60,7 +59,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - #endif - } - --static int once(char *URL, bool oldstyle) -+static CURLcode test_once(char *URL, bool oldstyle) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -71,28 +70,32 @@ static int once(char *URL, bool oldstyle) - struct WriteThis pooh; - struct WriteThis pooh2; - -- pooh.readptr = data; -- pooh.sizeleft = strlen(data); -+ pooh.readptr = testdata; -+ pooh.sizeleft = strlen(testdata); - - /* Fill in the file upload field */ - if(oldstyle) { -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "sendfile", -- CURLFORM_STREAM, &pooh, -- CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft, -- CURLFORM_FILENAME, "postit2.c", -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "sendfile", -+ CURLFORM_STREAM, &pooh, -+ CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft, -+ CURLFORM_FILENAME, "postit2.c", -+ CURLFORM_END); -+ ) - } - else { -- /* new style */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "sendfile alternative", -- CURLFORM_STREAM, &pooh, -- CURLFORM_CONTENTLEN, (curl_off_t)pooh.sizeleft, -- CURLFORM_FILENAME, "file name 2", -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ /* new style */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "sendfile alternative", -+ CURLFORM_STREAM, &pooh, -+ CURLFORM_CONTENTLEN, (curl_off_t)pooh.sizeleft, -+ CURLFORM_FILENAME, "file name 2", -+ CURLFORM_END); -+ ) - } - - if(formrc) -@@ -101,55 +104,61 @@ static int once(char *URL, bool oldstyle) - /* Now add the same data with another name and make it not look like - a file upload but still using the callback */ - -- pooh2.readptr = data; -- pooh2.sizeleft = strlen(data); -- -- /* Fill in the file upload field */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "callbackdata", -- CURLFORM_STREAM, &pooh2, -- CURLFORM_CONTENTSLENGTH, (long)pooh2.sizeleft, -- CURLFORM_END); -+ pooh2.readptr = testdata; -+ pooh2.sizeleft = strlen(testdata); - -+ CURL_IGNORE_DEPRECATION( -+ /* Fill in the file upload field */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "callbackdata", -+ CURLFORM_STREAM, &pooh2, -+ CURLFORM_CONTENTSLENGTH, (long)pooh2.sizeleft, -+ CURLFORM_END); -+ ) - if(formrc) - printf("curl_formadd(2) = %d\n", (int)formrc); - -- /* Fill in the filename field */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "filename", -- CURLFORM_COPYCONTENTS, "postit2.c", -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ /* Fill in the filename field */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "filename", -+ CURLFORM_COPYCONTENTS, "postit2.c", -+ CURLFORM_END); -+ ) - if(formrc) - printf("curl_formadd(3) = %d\n", (int)formrc); - -- /* Fill in a submit field too */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "submit", -- CURLFORM_COPYCONTENTS, "send", -- CURLFORM_CONTENTTYPE, "text/plain", -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ /* Fill in a submit field too */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "submit", -+ CURLFORM_COPYCONTENTS, "send", -+ CURLFORM_CONTENTTYPE, "text/plain", -+ CURLFORM_END); -+ ) - if(formrc) - printf("curl_formadd(4) = %d\n", (int)formrc); - -- formrc = curl_formadd(&formpost, &lastptr, -- CURLFORM_COPYNAME, "somename", -- CURLFORM_BUFFER, "somefile.txt", -- CURLFORM_BUFFERPTR, "blah blah", -- CURLFORM_BUFFERLENGTH, (long)9, -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ formrc = curl_formadd(&formpost, &lastptr, -+ CURLFORM_COPYNAME, "somename", -+ CURLFORM_BUFFER, "somefile.txt", -+ CURLFORM_BUFFERPTR, "blah blah", -+ CURLFORM_BUFFERLENGTH, (long)9, -+ CURLFORM_END); -+ ) - if(formrc) - printf("curl_formadd(5) = %d\n", (int)formrc); - - curl = curl_easy_init(); - if(!curl) { - fprintf(stderr, "curl_easy_init() failed\n"); -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_formfree(formpost); -+ ) - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } -@@ -166,8 +175,10 @@ static int once(char *URL, bool oldstyle) - /* we want to use our own read function */ - test_setopt(curl, CURLOPT_READFUNCTION, read_callback); - -- /* send a multi-part formpost */ -- test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* send a multi-part formpost */ -+ test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ ) - - /* get verbose debug output please */ - test_setopt(curl, CURLOPT_VERBOSE, 1L); -@@ -180,27 +191,31 @@ static int once(char *URL, bool oldstyle) - - test_cleanup: - -- /* always cleanup */ -- curl_easy_cleanup(curl); -+ CURL_IGNORE_DEPRECATION( -+ /* always cleanup */ -+ curl_easy_cleanup(curl); -+ ) - -- /* now cleanup the formpost chain */ -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* now cleanup the formpost chain */ -+ curl_formfree(formpost); -+ ) - - return res; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - -- res = once(URL, TRUE); /* old */ -+ res = test_once(URL, TRUE); /* old */ - if(!res) -- res = once(URL, FALSE); /* new */ -+ res = test_once(URL, FALSE); /* new */ - - curl_global_cleanup(); - -diff --git a/tests/libtest/lib555.c b/tests/libtest/lib555.c -index 2e595b686..7a16e2e2c 100644 ---- a/tests/libtest/lib555.c -+++ b/tests/libtest/lib555.c -@@ -76,9 +76,9 @@ static curlioerr ioctlcallback(CURL *handle, - } - - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - int counter = 0; - CURLM *m = NULL; -diff --git a/tests/libtest/lib556.c b/tests/libtest/lib556.c -index ead6529ea..06532c616 100644 ---- a/tests/libtest/lib556.c -+++ b/tests/libtest/lib556.c -@@ -37,7 +37,7 @@ - #define STDERR_FILENO 2 - #endif - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -65,29 +65,36 @@ int test(char *URL) - const char *request = - "GET /556 HTTP/1.1\r\n" - "Host: ninja\r\n\r\n"; -- size_t iolen = 0; -- -- res = curl_easy_send(curl, request, strlen(request), &iolen); -- -- if(!res) { -- /* we assume that sending always work */ -+ const char *sbuf = request; -+ size_t sblen = strlen(request); -+ size_t nwritten = 0, nread = 0; -+ -+ do { -+ char buf[1024]; -+ -+ if(sblen) { -+ res = curl_easy_send(curl, sbuf, sblen, &nwritten); -+ if(res && res != CURLE_AGAIN) -+ break; -+ if(nwritten > 0) { -+ sbuf += nwritten; -+ sblen -= nwritten; -+ } -+ } - -- do { -- char buf[1024]; -- /* busy-read like crazy */ -- res = curl_easy_recv(curl, buf, sizeof(buf), &iolen); -+ /* busy-read like crazy */ -+ res = curl_easy_recv(curl, buf, sizeof(buf), &nread); - -- if(iolen) { -- /* send received stuff to stdout */ -- if(!write(STDOUT_FILENO, buf, iolen)) -- break; -- } -+ if(nread) { -+ /* send received stuff to stdout */ -+ if(!write(STDOUT_FILENO, buf, nread)) -+ break; -+ } - -- } while((res == CURLE_OK && iolen) || (res == CURLE_AGAIN)); -- } -+ } while((res == CURLE_OK && nread) || (res == CURLE_AGAIN)); - -- if(iolen) -- res = (CURLcode)TEST_ERR_FAILURE; -+ if(res && res != CURLE_AGAIN) -+ res = TEST_ERR_FAILURE; - } - - test_cleanup: -@@ -95,5 +102,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib557.c b/tests/libtest/lib557.c -index c15769474..d84626036 100644 ---- a/tests/libtest/lib557.c -+++ b/tests/libtest/lib557.c -@@ -27,8 +27,6 @@ - * curl_m*printf formatting capabilities and handling of some data types. - */ - --#define CURL_NO_FMT_CHECKS /* disable compiler *printf format checks */ -- - #include "test.h" - - #include -@@ -39,6 +37,15 @@ - - #include "memdebug.h" - -+#if defined(__GNUC__) || defined(__clang__) -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wformat" -+#pragma GCC diagnostic ignored "-Wformat-extra-args" -+#if !defined(__clang__) && __GNUC__ >= 7 -+#pragma GCC diagnostic ignored "-Wformat-overflow" -+#endif -+#endif -+ - #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG) - # define MPRNT_SUFFIX_CURL_OFF_T LL - #else -@@ -150,7 +157,7 @@ static int test_unsigned_short_formatting(void) - - for(i = 1; i <= num_ushort_tests; i++) { - -- for(j = 0; jServer ANNOUNCE functionality (PUT style) - */ --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - int sdp; - FILE *sdpf = NULL; -diff --git a/tests/libtest/lib569.c b/tests/libtest/lib569.c -index da95bb955..847116a34 100644 ---- a/tests/libtest/lib569.c -+++ b/tests/libtest/lib569.c -@@ -33,9 +33,9 @@ static char *suburl(const char *base, int i) - /* - * Test Session ID capture - */ --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - char *stream_uri = NULL; - char *rtsp_session_id; -diff --git a/tests/libtest/lib570.c b/tests/libtest/lib570.c -index 392c398a8..3d15e9bcf 100644 ---- a/tests/libtest/lib570.c -+++ b/tests/libtest/lib570.c -@@ -30,9 +30,9 @@ static char *suburl(const char *base, int i) - return curl_maprintf("%s%.4d", base, i); - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - int request = 1; - char *stream_uri = NULL; -@@ -104,11 +104,11 @@ int test(char *URL) - - res = curl_easy_perform(curl); - if(res == CURLE_RTSP_SESSION_ERROR) { -- res = 0; -+ res = CURLE_OK; - } - else { - fprintf(stderr, "Failed to detect a Session ID mismatch"); -- res = 1; -+ res = (CURLcode)1; - } - - test_cleanup: -diff --git a/tests/libtest/lib571.c b/tests/libtest/lib571.c -index c4ae67d4b..b7868e0a3 100644 ---- a/tests/libtest/lib571.c -+++ b/tests/libtest/lib571.c -@@ -52,7 +52,7 @@ static const char *RTP_DATA = "$_1234\n\0Rsdf"; - - static int rtp_packet_count = 0; - --static size_t rtp_write(void *ptr, size_t size, size_t nmemb, void *stream) -+static size_t rtp_write(char *ptr, size_t size, size_t nmemb, void *stream) - { - char *data = (char *)ptr; - int channel = RTP_PKT_CHANNEL(data); -@@ -100,9 +100,9 @@ static char *suburl(const char *base, int i) - return curl_maprintf("%s%.4d", base, i); - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - char *stream_uri = NULL; - int request = 1; -diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c -index b199c4895..f28b741b0 100644 ---- a/tests/libtest/lib572.c -+++ b/tests/libtest/lib572.c -@@ -41,9 +41,9 @@ static char *suburl(const char *base, int i) - /* - * Test GET_PARAMETER: PUT, HEARTBEAT, and POST - */ --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - int params; - FILE *paramsf = NULL; -diff --git a/tests/libtest/lib573.c b/tests/libtest/lib573.c -index af140e2db..04bc9ded7 100644 ---- a/tests/libtest/lib573.c -+++ b/tests/libtest/lib573.c -@@ -34,11 +34,11 @@ - * Get a single URL without select(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *c = NULL; - CURLM *m = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int running = 1; - double connect_time = 0.0; - double dbl_epsilon; -diff --git a/tests/libtest/lib574.c b/tests/libtest/lib574.c -index 79a9b167e..0d107ef11 100644 ---- a/tests/libtest/lib574.c -+++ b/tests/libtest/lib574.c -@@ -31,14 +31,14 @@ static int new_fnmatch(void *ptr, - const char *pattern, const char *string) - { - (void)ptr; -- (void)pattern; -- (void)string; -+ fprintf(stderr, "lib574: match string '%s' against pattern '%s'\n", -+ string, pattern); - return CURL_FNMATCHFUNC_MATCH; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - CURL *curl; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { -diff --git a/tests/libtest/lib575.c b/tests/libtest/lib575.c -index 1de6e3284..d64f70d73 100644 ---- a/tests/libtest/lib575.c -+++ b/tests/libtest/lib575.c -@@ -37,12 +37,12 @@ - * 3. with multi interface - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURL *duphandle = NULL; - CURLM *mhandle = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int still_running = 0; - - start_test_timing(); -diff --git a/tests/libtest/lib576.c b/tests/libtest/lib576.c -index 7bc475087..db5a41aad 100644 ---- a/tests/libtest/lib576.c -+++ b/tests/libtest/lib576.c -@@ -32,8 +32,9 @@ struct chunk_data { - }; - - static --long chunk_bgn(const struct curl_fileinfo *finfo, void *ptr, int remains) -+long chunk_bgn(const void *f, void *ptr, int remains) - { -+ const struct curl_fileinfo *finfo = f; - struct chunk_data *ch_d = ptr; - ch_d->remains = remains; - -@@ -94,7 +95,7 @@ long chunk_end(void *ptr) - return CURL_CHUNK_END_FUNC_OK; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib578.c b/tests/libtest/lib578.c -index 7c6af9945..6be64a1aa 100644 ---- a/tests/libtest/lib578.c -+++ b/tests/libtest/lib578.c -@@ -26,9 +26,9 @@ - #include "memdebug.h" - - /* The size of data should be kept below MAX_INITIAL_POST_SIZE! */ --static char data[]="this is a short string.\n"; -+static char testdata[]="this is a short string.\n"; - --static size_t data_size = sizeof(data) / sizeof(char); -+static size_t data_size = sizeof(testdata) / sizeof(char); - - static int progress_callback(void *clientp, double dltotal, double dlnow, - double ultotal, double ulnow) -@@ -50,7 +50,7 @@ static int progress_callback(void *clientp, double dltotal, double dlnow, - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -75,7 +75,7 @@ int test(char *URL) - - /* Set the expected POST size */ - test_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)data_size); -- test_setopt(curl, CURLOPT_POSTFIELDS, data); -+ test_setopt(curl, CURLOPT_POSTFIELDS, testdata); - - /* we want to use our own progress function */ - CURL_IGNORE_DEPRECATION( -diff --git a/tests/libtest/lib579.c b/tests/libtest/lib579.c -index 5f962179a..9b1591fad 100644 ---- a/tests/libtest/lib579.c -+++ b/tests/libtest/lib579.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static const char * const post[]={ -+static const char * const testpost[]={ - "one", - "two", - "three", -@@ -38,31 +38,38 @@ struct WriteThis { - int counter; - }; - -+static bool started = FALSE; -+static size_t last_ul = 0; -+static size_t last_ul_total = 0; -+ -+static void progress_final_report(void) -+{ -+ FILE *moo = fopen(libtest_arg2, "ab"); -+ fprintf(moo, "Progress: end UL %zu/%zu\n", last_ul, last_ul_total); -+ started = FALSE; -+ fclose(moo); -+} -+ - static int progress_callback(void *clientp, double dltotal, double dlnow, - double ultotal, double ulnow) - { -- static int prev_ultotal = -1; -- static int prev_ulnow = -1; - (void)clientp; /* UNUSED */ - (void)dltotal; /* UNUSED */ - (void)dlnow; /* UNUSED */ - -- /* to avoid depending on timing, which will cause this progress function to -- get called a different number of times depending on circumstances, we -- only log these lines if the numbers are different from the previous -- invoke */ -- if((prev_ultotal != (int)ultotal) || -- (prev_ulnow != (int)ulnow)) { -+ if(started && ulnow <= 0.0 && last_ul) { -+ progress_final_report(); -+ } - -+ last_ul = (size_t)ulnow; -+ last_ul_total = (size_t)ultotal; -+ if(!started) { - FILE *moo = fopen(libtest_arg2, "ab"); -- if(moo) { -- fprintf(moo, "Progress callback called with UL %d out of %d\n", -- (int)ulnow, (int)ultotal); -- fclose(moo); -- } -- prev_ulnow = (int) ulnow; -- prev_ultotal = (int) ultotal; -+ fprintf(moo, "Progress: start UL %zu/%zu\n", last_ul, last_ul_total); -+ started = TRUE; -+ fclose(moo); - } -+ - return 0; - } - -@@ -74,7 +81,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - if(size*nmemb < 1) - return 0; - -- data = post[pooh->counter]; -+ data = testpost[pooh->counter]; - - if(data) { - size_t len = strlen(data); -@@ -85,7 +92,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -146,6 +153,8 @@ int test(char *URL) - /* Perform the request, res will get the return code */ - res = curl_easy_perform(curl); - -+ progress_final_report(); -+ - test_cleanup: - - /* clean up the headers list */ -diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c -index 8fe6402a4..d1609a83d 100644 ---- a/tests/libtest/lib582.c -+++ b/tests/libtest/lib582.c -@@ -31,15 +31,13 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --struct Sockets --{ -+struct Sockets { - curl_socket_t *sockets; - int count; /* number of sockets actually stored in array */ - int max_count; /* max number of sockets that fit in allocated array */ - }; - --struct ReadWriteSockets --{ -+struct ReadWriteSockets { - struct Sockets read, write; - }; - -@@ -220,9 +218,9 @@ static void checkFdSet(CURLM *curl, struct Sockets *sockets, fd_set *fdset, - } - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - CURL *curl = NULL; - FILE *hd_src = NULL; - int hd; -diff --git a/tests/libtest/lib583.c b/tests/libtest/lib583.c -index ba44b5d25..0ccf5c65a 100644 ---- a/tests/libtest/lib583.c -+++ b/tests/libtest/lib583.c -@@ -32,7 +32,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - int stillRunning; - CURLM *multiHandle = NULL; -@@ -87,5 +87,5 @@ test_cleanup: - curl_multi_cleanup(multiHandle); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib586.c b/tests/libtest/lib586.c -index f6e607737..c6d9f7d7f 100644 ---- a/tests/libtest/lib586.c -+++ b/tests/libtest/lib586.c -@@ -38,8 +38,8 @@ struct userdata { - }; - - /* lock callback */ --static void my_lock(CURL *handle, curl_lock_data data, -- curl_lock_access laccess, void *useptr) -+static void test_lock(CURL *handle, curl_lock_data data, -+ curl_lock_access laccess, void *useptr) - { - const char *what; - struct userdata *user = (struct userdata *)useptr; -@@ -69,7 +69,7 @@ static void my_lock(CURL *handle, curl_lock_data data, - } - - /* unlock callback */ --static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) -+static void test_unlock(CURL *handle, curl_lock_data data, void *useptr) - { - const char *what; - struct userdata *user = (struct userdata *)useptr; -@@ -96,7 +96,7 @@ static void my_unlock(CURL *handle, curl_lock_data data, void *useptr) - } - - /* the dummy thread function */ --static void *fire(void *ptr) -+static void *test_fire(void *ptr) - { - CURLcode code; - struct Tdata *tdata = (struct Tdata*)ptr; -@@ -129,7 +129,7 @@ static void *fire(void *ptr) - } - - /* test function */ --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res = CURLE_OK; - CURLSHcode scode = CURLSHE_OK; -@@ -160,11 +160,11 @@ int test(char *URL) - - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_LOCKFUNC\n"); -- scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock); -+ scode = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, test_lock); - } - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_UNLOCKFUNC\n"); -- scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock); -+ scode = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, test_unlock); - } - if(CURLSHE_OK == scode) { - printf("CURLSHOPT_USERDATA\n"); -@@ -193,11 +193,11 @@ int test(char *URL) - - /* simulate thread, direct call of "thread" function */ - printf("*** run %d\n",i); -- fire(&tdata); -+ test_fire(&tdata); - } - - -- /* fetch a another one */ -+ /* fetch another one */ - printf("*** run %d\n", i); - curl = curl_easy_init(); - if(!curl) { -diff --git a/tests/libtest/lib589.c b/tests/libtest/lib589.c -index 3a17e31c6..eb800f857 100644 ---- a/tests/libtest/lib589.c -+++ b/tests/libtest/lib589.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -72,5 +72,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib590.c b/tests/libtest/lib590.c -index babcd1952..cda3b029e 100644 ---- a/tests/libtest/lib590.c -+++ b/tests/libtest/lib590.c -@@ -38,7 +38,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -69,5 +69,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib591.c b/tests/libtest/lib591.c -index 445bb0a9d..742baf202 100644 ---- a/tests/libtest/lib591.c -+++ b/tests/libtest/lib591.c -@@ -35,11 +35,11 @@ - - #define TEST_HANG_TIMEOUT 60 * 1000 - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - CURLM *multi = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int running; - int msgs_left; - CURLMsg *msg; -diff --git a/tests/libtest/lib597.c b/tests/libtest/lib597.c -index 77ab89413..71535b041 100644 ---- a/tests/libtest/lib597.c -+++ b/tests/libtest/lib597.c -@@ -40,11 +40,11 @@ - * with function curl_multi_info_read(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - CURLM *multi = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - int running; - int msgs_left; - CURLMsg *msg; -diff --git a/tests/libtest/lib598.c b/tests/libtest/lib598.c -index 62b365514..8c67076b4 100644 ---- a/tests/libtest/lib598.c -+++ b/tests/libtest/lib598.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -70,5 +70,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib599.c b/tests/libtest/lib599.c -index 6002e0fb0..391b9f2d5 100644 ---- a/tests/libtest/lib599.c -+++ b/tests/libtest/lib599.c -@@ -41,7 +41,7 @@ static int progress_callback(void *clientp, double dltotal, - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib643.c b/tests/libtest/lib643.c -index efd508f8d..bd7f5e0f8 100644 ---- a/tests/libtest/lib643.c -+++ b/tests/libtest/lib643.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]= -+static char testdata[]= - "dummy\n"; - - struct WriteThis { -@@ -56,7 +56,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --static int once(char *URL, bool oldstyle) -+static CURLcode test_once(char *URL, bool oldstyle) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -67,9 +67,9 @@ static int once(char *URL, bool oldstyle) - struct WriteThis pooh2; - curl_off_t datasize = -1; - -- pooh.readptr = data; -+ pooh.readptr = testdata; - #ifndef LIB645 -- datasize = (curl_off_t)strlen(data); -+ datasize = (curl_off_t)strlen(testdata); - #endif - pooh.sizeleft = datasize; - -@@ -122,9 +122,9 @@ static int once(char *URL, bool oldstyle) - /* Now add the same data with another name and make it not look like - a file upload but still using the callback */ - -- pooh2.readptr = data; -+ pooh2.readptr = testdata; - #ifndef LIB645 -- datasize = (curl_off_t)strlen(data); -+ datasize = (curl_off_t)strlen(testdata); - #endif - pooh2.sizeleft = datasize; - -@@ -223,7 +223,7 @@ test_cleanup: - return res; - } - --static int cyclic_add(void) -+static CURLcode cyclic_add(void) - { - CURL *easy = curl_easy_init(); - curl_mime *mime = curl_mime_init(easy); -@@ -242,23 +242,23 @@ static int cyclic_add(void) - curl_easy_cleanup(easy); - if(a1 != CURLE_BAD_FUNCTION_ARGUMENT) - /* that should have failed */ -- return 1; -+ return (CURLcode)1; - -- return 0; -+ return CURLE_OK; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res; -+ CURLcode res; - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - -- res = once(URL, TRUE); /* old */ -+ res = test_once(URL, TRUE); /* old */ - if(!res) -- res = once(URL, FALSE); /* new */ -+ res = test_once(URL, FALSE); /* new */ - - if(!res) - res = cyclic_add(); -diff --git a/tests/libtest/lib650.c b/tests/libtest/lib650.c -index 14c79e94b..f0d459e66 100644 ---- a/tests/libtest/lib650.c -+++ b/tests/libtest/lib650.c -@@ -21,15 +21,14 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ --#define CURL_DISABLE_DEPRECATION /* Using and testing the form api */ - #include "test.h" - - #include "memdebug.h" - --static char data[] = -+static char testdata[] = - "this is what we post to the silly web server"; - --static const char name[] = "fieldname"; -+static const char testname[] = "fieldname"; - - - /* This test attempts to use all form API features that are not -@@ -47,7 +46,7 @@ static size_t count_chars(void *userp, const char *buf, size_t len) - } - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = TEST_ERR_MAJOR_BAD; -@@ -80,34 +79,36 @@ int test(char *URL) - goto test_cleanup; - } - headers = headers2; -- formrc = curl_formadd(&formpost, &lastptr, -- CURLFORM_COPYNAME, &name, -- CURLFORM_COPYCONTENTS, &data, -- CURLFORM_CONTENTHEADER, headers, -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ formrc = curl_formadd(&formpost, &lastptr, -+ CURLFORM_COPYNAME, &testname, -+ CURLFORM_COPYCONTENTS, &testdata, -+ CURLFORM_CONTENTHEADER, headers, -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(1) = %d\n", (int) formrc); - goto test_cleanup; - } - -- contentlength = (long)(strlen(data) - 1); -- -- /* Use a form array for the non-copy test. */ -- formarray[0].option = CURLFORM_PTRCONTENTS; -- formarray[0].value = data; -- formarray[1].option = CURLFORM_CONTENTSLENGTH; -- formarray[1].value = (char *)(size_t)contentlength; -- formarray[2].option = CURLFORM_END; -- formarray[2].value = NULL; -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_PTRNAME, name, -- CURLFORM_NAMELENGTH, strlen(name) - 1, -- CURLFORM_ARRAY, formarray, -- CURLFORM_FILENAME, "remotefile.txt", -- CURLFORM_END); -- -+ contentlength = (long)(strlen(testdata) - 1); -+ -+ CURL_IGNORE_DEPRECATION( -+ /* Use a form array for the non-copy test. */ -+ formarray[0].option = CURLFORM_PTRCONTENTS; -+ formarray[0].value = testdata; -+ formarray[1].option = CURLFORM_CONTENTSLENGTH; -+ formarray[1].value = (char *)(size_t)contentlength; -+ formarray[2].option = CURLFORM_END; -+ formarray[2].value = NULL; -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_PTRNAME, testname, -+ CURLFORM_NAMELENGTH, strlen(testname) - 1, -+ CURLFORM_ARRAY, formarray, -+ CURLFORM_FILENAME, "remotefile.txt", -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(2) = %d\n", (int) formrc); - goto test_cleanup; -@@ -116,59 +117,67 @@ int test(char *URL) - /* Now change in-memory data to affect CURLOPT_PTRCONTENTS value. - Copied values (first field) must not be affected. - CURLOPT_PTRNAME actually copies the name thus we do not test this here. */ -- data[0]++; -- -- /* Check multi-files and content type propagation. */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "multifile", -- CURLFORM_FILE, libtest_arg2, /* Set in first.c. */ -- CURLFORM_FILE, libtest_arg2, -- CURLFORM_CONTENTTYPE, "text/whatever", -- CURLFORM_FILE, libtest_arg2, -- CURLFORM_END); -- -+ testdata[0]++; -+ -+ CURL_IGNORE_DEPRECATION( -+ /* Check multi-files and content type propagation. */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "multifile", -+ CURLFORM_FILE, libtest_arg2, /* Set in first.c. */ -+ CURLFORM_FILE, libtest_arg2, -+ CURLFORM_CONTENTTYPE, "text/whatever", -+ CURLFORM_FILE, libtest_arg2, -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(3) = %d\n", (int) formrc); - goto test_cleanup; - } - -- /* Check data from file content. */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "filecontents", -- CURLFORM_FILECONTENT, libtest_arg2, -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ /* Check data from file content. */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "filecontents", -+ CURLFORM_FILECONTENT, libtest_arg2, -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(4) = %d\n", (int) formrc); - goto test_cleanup; - } - -- /* Measure the current form length. -- * This is done before including stdin data because we want to reuse it -- * and stdin cannot be rewound. -- */ -- curl_formget(formpost, (void *) &formlength, count_chars); -+ CURL_IGNORE_DEPRECATION( -+ /* Measure the current form length. -+ * This is done before including stdin data because we want to reuse it -+ * and stdin cannot be rewound. -+ */ -+ curl_formget(formpost, (void *) &formlength, count_chars); -+ ) - - /* Include length in data for external check. */ - curl_msnprintf(flbuf, sizeof(flbuf), "%lu", (unsigned long) formlength); -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "formlength", -- CURLFORM_COPYCONTENTS, &flbuf, -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "formlength", -+ CURLFORM_COPYCONTENTS, &flbuf, -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(5) = %d\n", (int) formrc); - goto test_cleanup; - } - -- /* Check stdin (may be problematic on some platforms). */ -- formrc = curl_formadd(&formpost, -- &lastptr, -- CURLFORM_COPYNAME, "standardinput", -- CURLFORM_FILE, "-", -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ /* Check stdin (may be problematic on some platforms). */ -+ formrc = curl_formadd(&formpost, -+ &lastptr, -+ CURLFORM_COPYNAME, "standardinput", -+ CURLFORM_FILE, "-", -+ CURLFORM_END); -+ ) - if(formrc) { - printf("curl_formadd(6) = %d\n", (int) formrc); - goto test_cleanup; -@@ -183,8 +192,10 @@ int test(char *URL) - /* First set the URL that is about to receive our POST. */ - test_setopt(curl, CURLOPT_URL, URL); - -- /* send a multi-part formpost */ -- test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* send a multi-part formpost */ -+ test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ ) - - /* get verbose debug output please */ - test_setopt(curl, CURLOPT_VERBOSE, 1L); -@@ -203,8 +214,10 @@ test_cleanup: - /* always cleanup */ - curl_easy_cleanup(curl); - -- /* now cleanup the formpost chain */ -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* now cleanup the formpost chain */ -+ curl_formfree(formpost); -+ ) - curl_slist_free_all(headers); - - curl_global_cleanup(); -diff --git a/tests/libtest/lib651.c b/tests/libtest/lib651.c -index 2e45ccc21..7fb97def8 100644 ---- a/tests/libtest/lib651.c -+++ b/tests/libtest/lib651.c -@@ -21,14 +21,13 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ --#define CURL_DISABLE_DEPRECATION /* Using and testing the form api */ - #include "test.h" - - #include "memdebug.h" - --static char buffer[17000]; /* more than 16K */ -+static char testbuf[17000]; /* more than 16K */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -38,24 +37,25 @@ int test(char *URL) - - /* create a buffer with AAAA...BBBBB...CCCC...etc */ - int i; -- int size = (int)sizeof(buffer)/1000; -+ int size = (int)sizeof(testbuf)/1000; - - for(i = 0; i < size ; i++) -- memset(&buffer[i * 1000], 65 + i, 1000); -+ memset(&testbuf[i * 1000], 65 + i, 1000); - -- buffer[ sizeof(buffer)-1] = 0; /* null-terminate */ -+ testbuf[sizeof(testbuf)-1] = 0; /* null-terminate */ - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - -- /* Check proper name and data copying. */ -- formrc = curl_formadd(&formpost, &lastptr, -- CURLFORM_COPYNAME, "hello", -- CURLFORM_COPYCONTENTS, buffer, -- CURLFORM_END); -- -+ CURL_IGNORE_DEPRECATION( -+ /* Check proper name and data copying. */ -+ formrc = curl_formadd(&formpost, &lastptr, -+ CURLFORM_COPYNAME, "hello", -+ CURLFORM_COPYCONTENTS, testbuf, -+ CURLFORM_END); -+ ) - if(formrc) - printf("curl_formadd(1) = %d\n", (int) formrc); - -@@ -63,7 +63,9 @@ int test(char *URL) - curl = curl_easy_init(); - if(!curl) { - fprintf(stderr, "curl_easy_init() failed\n"); -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_formfree(formpost); -+ ) - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } -@@ -71,8 +73,10 @@ int test(char *URL) - /* First set the URL that is about to receive our POST. */ - test_setopt(curl, CURLOPT_URL, URL); - -- /* send a multi-part formpost */ -- test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* send a multi-part formpost */ -+ test_setopt(curl, CURLOPT_HTTPPOST, formpost); -+ ) - - /* get verbose debug output please */ - test_setopt(curl, CURLOPT_VERBOSE, 1L); -@@ -88,8 +92,10 @@ test_cleanup: - /* always cleanup */ - curl_easy_cleanup(curl); - -- /* now cleanup the formpost chain */ -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* now cleanup the formpost chain */ -+ curl_formfree(formpost); -+ ) - - curl_global_cleanup(); - -diff --git a/tests/libtest/lib652.c b/tests/libtest/lib652.c -index 7a100b731..591aa7269 100644 ---- a/tests/libtest/lib652.c -+++ b/tests/libtest/lib652.c -@@ -25,9 +25,9 @@ - - #include "memdebug.h" - --static char buffer[17000]; /* more than 16K */ -+static char testbuf[17000]; /* more than 16K */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_OK; -@@ -35,12 +35,12 @@ int test(char *URL) - curl_mimepart *part; - struct curl_slist *recipients = NULL; - -- /* create a buffer with AAAA...BBBBB...CCCC...etc */ -+ /* create a testbuf with AAAA...BBBBB...CCCC...etc */ - int i; -- int size = (int)sizeof(buffer) / 10; -+ int size = (int)sizeof(testbuf) / 10; - - for(i = 0; i < size ; i++) -- memset(&buffer[i * 10], 65 + (i % 26), 10); -+ memset(&testbuf[i * 10], 65 + (i % 26), 10); - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); -@@ -50,7 +50,7 @@ int test(char *URL) - curl = curl_easy_init(); - if(!curl) { - fprintf(stderr, "curl_easy_init() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - -@@ -58,13 +58,13 @@ int test(char *URL) - mime = curl_mime_init(curl); - if(!mime) { - fprintf(stderr, "curl_mime_init() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - part = curl_mime_addpart(mime); - if(!part) { - fprintf(stderr, "curl_mime_addpart() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - res = curl_mime_filename(part, "myfile.jpg"); -@@ -77,7 +77,7 @@ int test(char *URL) - fprintf(stderr, "curl_mime_type() failed\n"); - goto test_cleanup; - } -- res = curl_mime_data(part, buffer, sizeof(buffer)); -+ res = curl_mime_data(part, testbuf, sizeof(testbuf)); - if(res) { - fprintf(stderr, "curl_mime_data() failed\n"); - goto test_cleanup; -diff --git a/tests/libtest/lib653.c b/tests/libtest/lib653.c -index 8a6fff341..a1be0df16 100644 ---- a/tests/libtest/lib653.c -+++ b/tests/libtest/lib653.c -@@ -28,10 +28,10 @@ - #include "memdebug.h" - - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curls = NULL; -- int res = 0; -+ CURLcode res = CURLE_OK; - curl_mimepart *field = NULL; - curl_mime *mime = NULL; - -@@ -61,5 +61,5 @@ test_cleanup: - curl_mime_free(mime); - curl_easy_cleanup(curls); - curl_global_cleanup(); -- return (int) res; /* return the final return code */ -+ return res; /* return the final return code */ - } -diff --git a/tests/libtest/lib654.c b/tests/libtest/lib654.c -index 96551637d..66ec29d17 100644 ---- a/tests/libtest/lib654.c -+++ b/tests/libtest/lib654.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]= -+static char testdata[]= - "dummy\n"; - - struct WriteThis { -@@ -62,15 +62,14 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - CURL *easy2 = NULL; - curl_mime *mime = NULL; - curl_mimepart *part; - struct curl_slist *hdrs = NULL; -- CURLcode result; -- int res = TEST_ERR_FAILURE; -+ CURLcode res = TEST_ERR_FAILURE; - struct WriteThis pooh; - - /* -@@ -95,8 +94,8 @@ int test(char *URL) - test_setopt(easy, CURLOPT_HEADER, 1L); - - /* Prepare the callback structure. */ -- pooh.readptr = data; -- pooh.sizeleft = (curl_off_t) strlen(data); -+ pooh.readptr = testdata; -+ pooh.sizeleft = (curl_off_t) strlen(testdata); - pooh.freecount = 0; - - /* Build the mime tree. */ -@@ -131,19 +130,17 @@ int test(char *URL) - mime = NULL; /* Already cleaned up. */ - - /* Perform on the first handle: should not send any data. */ -- result = curl_easy_perform(easy); -- if(result) { -+ res = curl_easy_perform(easy); -+ if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform(original) failed\n"); -- res = (int) result; - goto test_cleanup; - } - - /* Perform on the second handle: if the bound mime structure has not been - duplicated properly, it should cause a valgrind error. */ -- result = curl_easy_perform(easy2); -- if(result) { -+ res = curl_easy_perform(easy2); -+ if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform(duplicated) failed\n"); -- res = (int) result; - goto test_cleanup; - } - -diff --git a/tests/libtest/lib655.c b/tests/libtest/lib655.c -index 83525e57d..79654cb07 100644 ---- a/tests/libtest/lib655.c -+++ b/tests/libtest/lib655.c -@@ -58,7 +58,7 @@ resolver_alloc_cb_pass(void *resolver_state, void *reserved, void *userdata) - return 0; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl; - CURLcode res = CURLE_OK; -@@ -110,5 +110,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib658.c b/tests/libtest/lib658.c -index 5be239f67..59d947e23 100644 ---- a/tests/libtest/lib658.c -+++ b/tests/libtest/lib658.c -@@ -31,7 +31,7 @@ - * Get a single URL without select(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib659.c b/tests/libtest/lib659.c -index 97efbec65..bdd879b02 100644 ---- a/tests/libtest/lib659.c -+++ b/tests/libtest/lib659.c -@@ -31,7 +31,7 @@ - * Get a single URL without select(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURLcode res = CURLE_OK; -diff --git a/tests/libtest/lib661.c b/tests/libtest/lib661.c -index 5145937ac..10df49888 100644 ---- a/tests/libtest/lib661.c -+++ b/tests/libtest/lib661.c -@@ -24,7 +24,7 @@ - #include "test.h" - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl = NULL; -@@ -164,5 +164,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib666.c b/tests/libtest/lib666.c -index 62590702e..dd172be4a 100644 ---- a/tests/libtest/lib666.c -+++ b/tests/libtest/lib666.c -@@ -25,9 +25,9 @@ - - #include "memdebug.h" - --static char buffer[17000]; /* more than 16K */ -+static char testbuf[17000]; /* more than 16K */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURLcode res = CURLE_OK; -@@ -37,12 +37,12 @@ int test(char *URL) - - /* Checks huge binary-encoded mime post. */ - -- /* Create a buffer with pseudo-binary data. */ -- for(i = 0; i < sizeof(buffer); i++) -+ /* Create a testbuf with pseudo-binary data. */ -+ for(i = 0; i < sizeof(testbuf); i++) - if(i % 77 == 76) -- buffer[i] = '\n'; -+ testbuf[i] = '\n'; - else -- buffer[i] = (char) (0x41 + i % 26); /* A...Z */ -+ testbuf[i] = (char) (0x41 + i % 26); /* A...Z */ - - if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); -@@ -52,7 +52,7 @@ int test(char *URL) - curl = curl_easy_init(); - if(!curl) { - fprintf(stderr, "curl_easy_init() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - -@@ -60,13 +60,13 @@ int test(char *URL) - mime = curl_mime_init(curl); - if(!mime) { - fprintf(stderr, "curl_mime_init() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - part = curl_mime_addpart(mime); - if(!part) { - fprintf(stderr, "curl_mime_addpart() failed\n"); -- res = (CURLcode) TEST_ERR_MAJOR_BAD; -+ res = TEST_ERR_MAJOR_BAD; - goto test_cleanup; - } - res = curl_mime_name(part, "upfile"); -@@ -79,7 +79,7 @@ int test(char *URL) - fprintf(stderr, "curl_mime_filename() failed\n"); - goto test_cleanup; - } -- res = curl_mime_data(part, buffer, sizeof(buffer)); -+ res = curl_mime_data(part, testbuf, sizeof(testbuf)); - if(res) { - fprintf(stderr, "curl_mime_data() failed\n"); - goto test_cleanup; -diff --git a/tests/libtest/lib667.c b/tests/libtest/lib667.c -index 076361add..d19060146 100644 ---- a/tests/libtest/lib667.c -+++ b/tests/libtest/lib667.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]= -+static char testdata[]= - "dummy"; - - struct WriteThis { -@@ -54,13 +54,12 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return 0; /* no more data left to deliver */ - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - curl_mime *mime = NULL; - curl_mimepart *part; -- CURLcode result; -- int res = TEST_ERR_FAILURE; -+ CURLcode res = TEST_ERR_FAILURE; - struct WriteThis pooh; - - /* -@@ -85,8 +84,8 @@ int test(char *URL) - test_setopt(easy, CURLOPT_HEADER, 1L); - - /* Prepare the callback structure. */ -- pooh.readptr = data; -- pooh.sizeleft = (curl_off_t) strlen(data); -+ pooh.readptr = testdata; -+ pooh.sizeleft = (curl_off_t) strlen(testdata); - - /* Build the mime tree. */ - mime = curl_mime_init(easy); -@@ -100,10 +99,9 @@ int test(char *URL) - test_setopt(easy, CURLOPT_MIMEPOST, mime); - - /* Send data. */ -- result = curl_easy_perform(easy); -- if(result) { -+ res = curl_easy_perform(easy); -+ if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed\n"); -- res = (int) result; - } - - test_cleanup: -diff --git a/tests/libtest/lib668.c b/tests/libtest/lib668.c -index 35ab758f3..141e0ea57 100644 ---- a/tests/libtest/lib668.c -+++ b/tests/libtest/lib668.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --static char data[]= "dummy"; -+static char testdata[]= "dummy"; - - struct WriteThis { - char *readptr; -@@ -48,13 +48,12 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return len; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *easy = NULL; - curl_mime *mime = NULL; - curl_mimepart *part; -- CURLcode result; -- int res = TEST_ERR_FAILURE; -+ CURLcode res = TEST_ERR_FAILURE; - struct WriteThis pooh1, pooh2; - - /* -@@ -78,8 +77,8 @@ int test(char *URL) - test_setopt(easy, CURLOPT_HEADER, 1L); - - /* Prepare the callback structures. */ -- pooh1.readptr = data; -- pooh1.sizeleft = (curl_off_t) strlen(data); -+ pooh1.readptr = testdata; -+ pooh1.sizeleft = (curl_off_t) strlen(testdata); - pooh2 = pooh1; - - /* Build the mime tree. */ -@@ -87,7 +86,7 @@ int test(char *URL) - part = curl_mime_addpart(mime); - curl_mime_name(part, "field1"); - /* Early end of data detection can be done because the data size is known. */ -- curl_mime_data_cb(part, (curl_off_t) strlen(data), -+ curl_mime_data_cb(part, (curl_off_t) strlen(testdata), - read_callback, NULL, NULL, &pooh1); - part = curl_mime_addpart(mime); - curl_mime_name(part, "field2"); -@@ -104,10 +103,9 @@ int test(char *URL) - test_setopt(easy, CURLOPT_MIMEPOST, mime); - - /* Send data. */ -- result = curl_easy_perform(easy); -- if(result) { -+ res = curl_easy_perform(easy); -+ if(res != CURLE_OK) { - fprintf(stderr, "curl_easy_perform() failed\n"); -- res = (int) result; - } - - test_cleanup: -diff --git a/tests/libtest/lib670.c b/tests/libtest/lib670.c -index b348343c2..e03e8abeb 100644 ---- a/tests/libtest/lib670.c -+++ b/tests/libtest/lib670.c -@@ -21,11 +21,6 @@ - * SPDX-License-Identifier: curl - * - ***************************************************************************/ -- --#if !defined(LIB670) && !defined(LIB671) --#define CURL_DISABLE_DEPRECATION /* Using and testing the form api */ --#endif -- - #include "test.h" - - #include -@@ -35,7 +30,7 @@ - #define PAUSE_TIME 5 - - --static const char name[] = "field"; -+static const char testname[] = "field"; - - struct ReadThis { - CURL *easy; -@@ -61,7 +56,7 @@ static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userp) - return CURL_READFUNC_PAUSE; - case 2: - delta = time(NULL) - pooh->origin; -- *ptr = delta >= PAUSE_TIME? '\x42': '\x41'; /* ASCII A or B. */ -+ *ptr = delta >= PAUSE_TIME ? '\x42' : '\x41'; /* ASCII A or B. */ - return 1; - case 3: - return 0; -@@ -97,7 +92,7 @@ static int xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, - } - #endif - --int test(char *URL) -+CURLcode test(char *URL) - { - #if defined(LIB670) || defined(LIB671) - curl_mime *mime = NULL; -@@ -116,8 +111,7 @@ int test(char *URL) - #endif - - struct ReadThis pooh; -- CURLcode result; -- int res = TEST_ERR_FAILURE; -+ CURLcode res = TEST_ERR_FAILURE; - - /* - * Check proper pausing/unpausing from a mime or form read callback. -@@ -145,11 +139,11 @@ int test(char *URL) - /* Build the mime tree. */ - mime = curl_mime_init(pooh.easy); - part = curl_mime_addpart(mime); -- result = curl_mime_name(part, name); -- if(result) { -+ res = curl_mime_name(part, testname); -+ if(res != CURLE_OK) { - fprintf(stderr, - "Something went wrong when building the mime structure: %d\n", -- (int) result); -+ res); - goto test_cleanup; - } - -@@ -157,15 +151,17 @@ int test(char *URL) - NULL, NULL, &pooh); - - /* Bind mime data to its easy handle. */ -- if(!res) -+ if(res == CURLE_OK) - test_setopt(pooh.easy, CURLOPT_MIMEPOST, mime); - #else -- /* Build the form. */ -- formrc = curl_formadd(&formpost, &lastptr, -- CURLFORM_COPYNAME, name, -- CURLFORM_STREAM, &pooh, -- CURLFORM_CONTENTLEN, (curl_off_t) 2, -- CURLFORM_END); -+ CURL_IGNORE_DEPRECATION( -+ /* Build the form. */ -+ formrc = curl_formadd(&formpost, &lastptr, -+ CURLFORM_COPYNAME, testname, -+ CURLFORM_STREAM, &pooh, -+ CURLFORM_CONTENTLEN, (curl_off_t) 2, -+ CURLFORM_END); -+ ) - if(formrc) { - fprintf(stderr, "curl_formadd() = %d\n", (int) formrc); - goto test_cleanup; -@@ -174,8 +170,10 @@ int test(char *URL) - /* We want to use our own read function. */ - test_setopt(pooh.easy, CURLOPT_READFUNCTION, read_callback); - -- /* Send a multi-part formpost. */ -- test_setopt(pooh.easy, CURLOPT_HTTPPOST, formpost); -+ CURL_IGNORE_DEPRECATION( -+ /* Send a multi-part formpost. */ -+ test_setopt(pooh.easy, CURLOPT_HTTPPOST, formpost); -+ ) - #endif - - #if defined(LIB670) || defined(LIB672) -@@ -233,8 +231,7 @@ int test(char *URL) - if(!msg) - break; - if(msg->msg == CURLMSG_DONE) { -- result = msg->data.result; -- res = (int) result; -+ res = msg->data.result; - } - } - -@@ -246,8 +243,7 @@ int test(char *URL) - test_setopt(pooh.easy, CURLOPT_XFERINFODATA, &pooh); - test_setopt(pooh.easy, CURLOPT_XFERINFOFUNCTION, xferinfo); - test_setopt(pooh.easy, CURLOPT_NOPROGRESS, 0L); -- result = curl_easy_perform(pooh.easy); -- res = (int) result; -+ res = curl_easy_perform(pooh.easy); - #endif - - -@@ -256,7 +252,9 @@ test_cleanup: - #if defined(LIB670) || defined(LIB671) - curl_mime_free(mime); - #else -- curl_formfree(formpost); -+ CURL_IGNORE_DEPRECATION( -+ curl_formfree(formpost); -+ ) - #endif - - curl_global_cleanup(); -diff --git a/tests/libtest/lib674.c b/tests/libtest/lib674.c -index 1a01d9c18..39e16e0f5 100644 ---- a/tests/libtest/lib674.c -+++ b/tests/libtest/lib674.c -@@ -31,7 +31,7 @@ - * Get a single URL without select(). - */ - --int test(char *URL) -+CURLcode test(char *URL) - { - CURL *handle = NULL; - CURL *handle2; -diff --git a/tests/libtest/lib676.c b/tests/libtest/lib676.c -index 478d5f3a1..fc292705a 100644 ---- a/tests/libtest/lib676.c -+++ b/tests/libtest/lib676.c -@@ -25,7 +25,7 @@ - - #include "memdebug.h" - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLcode res; - CURL *curl; -@@ -66,5 +66,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/lib677.c b/tests/libtest/lib677.c -index 6dc7e8e17..ebb9f4084 100644 ---- a/tests/libtest/lib677.c -+++ b/tests/libtest/lib677.c -@@ -27,10 +27,10 @@ - #include "warnless.h" - #include "memdebug.h" - --static const char cmd[] = "A1 IDLE\r\n"; --static char buf[1024]; -+static const char testcmd[] = "A1 IDLE\r\n"; -+static char testbuf[1024]; - --int test(char *URL) -+CURLcode test(char *URL) - { - CURLM *mcurl; - CURL *curl = NULL; -@@ -39,7 +39,7 @@ int test(char *URL) - time_t start = time(NULL); - int state = 0; - ssize_t pos = 0; -- int res = 0; -+ CURLcode res = CURLE_OK; - - global_init(CURL_GLOBAL_DEFAULT); - multi_init(mcurl); -@@ -75,15 +75,19 @@ int test(char *URL) - curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sock); - waitfd.fd = sock; - } -- curl_multi_wait(mcurl, &waitfd, sock == CURL_SOCKET_BAD ? 0 : 1, 500, -+ curl_multi_wait(mcurl, &waitfd, sock == CURL_SOCKET_BAD ? 0 : 1, 50, - &mrun); - if((sock != CURL_SOCKET_BAD) && (waitfd.revents & waitfd.events)) { - size_t len = 0; - - if(!state) { - CURLcode ec; -- ec = curl_easy_send(curl, cmd + pos, sizeof(cmd) - 1 - pos, &len); -- if(ec != CURLE_OK) { -+ ec = curl_easy_send(curl, testcmd + pos, -+ sizeof(testcmd) - 1 - pos, &len); -+ if(ec == CURLE_AGAIN) { -+ continue; -+ } -+ else if(ec) { - fprintf(stderr, "curl_easy_send() failed, with code %d (%s)\n", - (int)ec, curl_easy_strerror(ec)); - res = ec; -@@ -93,15 +97,18 @@ int test(char *URL) - pos += len; - else - pos = 0; -- if(pos == sizeof(cmd) - 1) { -+ if(pos == sizeof(testcmd) - 1) { - state++; - pos = 0; - } - } -- else if(pos < (ssize_t)sizeof(buf)) { -+ else if(pos < (ssize_t)sizeof(testbuf)) { - CURLcode ec; -- ec = curl_easy_recv(curl, buf + pos, sizeof(buf) - pos, &len); -- if(ec != CURLE_OK) { -+ ec = curl_easy_recv(curl, testbuf + pos, sizeof(testbuf) - pos, &len); -+ if(ec == CURLE_AGAIN) { -+ continue; -+ } -+ else if(ec) { - fprintf(stderr, "curl_easy_recv() failed, with code %d (%s)\n", - (int)ec, curl_easy_strerror(ec)); - res = ec; -@@ -116,7 +123,7 @@ int test(char *URL) - } - - if(state) { -- fwrite(buf, pos, 1, stdout); -+ fwrite(testbuf, pos, 1, stdout); - putchar('\n'); - } - -diff --git a/tests/libtest/lib678.c b/tests/libtest/lib678.c -index 942808e2a..9a8ab7670 100644 ---- a/tests/libtest/lib678.c -+++ b/tests/libtest/lib678.c -@@ -63,7 +63,7 @@ static int loadfile(const char *filename, void **filedata, size_t *filesize) - return data ? 1 : 0; - } - --static int test_cert_blob(const char *url, const char *cafile) -+static CURLcode test_cert_blob(const char *url, const char *cafile) - { - CURLcode code = CURLE_OUT_OF_MEMORY; - CURL *curl; -@@ -94,12 +94,12 @@ static int test_cert_blob(const char *url, const char *cafile) - } - curl_easy_cleanup(curl); - -- return (int)code; -+ return code; - } - --int test(char *URL) -+CURLcode test(char *URL) - { -- int res = 0; -+ CURLcode res = CURLE_OK; - curl_global_init(CURL_GLOBAL_DEFAULT); - if(!strcmp("check", URL)) { - CURL *e; -@@ -112,7 +112,7 @@ int test(char *URL) - printf("CURLOPT_CAINFO_BLOB is not supported\n"); - curl_easy_cleanup(e); - } -- res = (int)w; -+ res = w; - } - else - res = test_cert_blob(URL, libtest_arg2); -diff --git a/tests/libtest/libauthretry.c b/tests/libtest/libauthretry.c -index a71fe20ed..db648f35a 100644 ---- a/tests/libtest/libauthretry.c -+++ b/tests/libtest/libauthretry.c -@@ -60,13 +60,13 @@ test_cleanup: - static CURLcode send_wrong_password(CURL *curl, const char *url, int seq, - long auth_scheme) - { -- return send_request(curl, url, seq, auth_scheme, "testuser:wrongpass"); -+ return send_request(curl, url, seq, auth_scheme, "testuser:wrongpass"); - } - - static CURLcode send_right_password(CURL *curl, const char *url, int seq, - long auth_scheme) - { -- return send_request(curl, url, seq, auth_scheme, "testuser:testpass"); -+ return send_request(curl, url, seq, auth_scheme, "testuser:testpass"); - } - - static long parse_auth_name(const char *arg) -@@ -82,7 +82,7 @@ static long parse_auth_name(const char *arg) - return CURLAUTH_NONE; - } - --int test(char *url) -+CURLcode test(char *url) - { - CURLcode res; - CURL *curl = NULL; -@@ -145,5 +145,5 @@ test_cleanup: - curl_easy_cleanup(curl); - curl_global_cleanup(); - -- return (int)res; -+ return res; - } -diff --git a/tests/libtest/libntlmconnect.c b/tests/libtest/libntlmconnect.c -index 462b5481c..9cbcb50bb 100644 ---- a/tests/libtest/libntlmconnect.c -+++ b/tests/libtest/libntlmconnect.c -@@ -33,31 +33,31 @@ - #define TEST_HANG_TIMEOUT 60 * 1000 - #define MAX_EASY_HANDLES 3 - --static int counter[MAX_EASY_HANDLES]; --static CURL *easy[MAX_EASY_HANDLES]; --static curl_socket_t sockets[MAX_EASY_HANDLES]; --static int res = 0; -+static int ntlm_counter[MAX_EASY_HANDLES]; -+static CURL *ntlm_easy[MAX_EASY_HANDLES]; -+static curl_socket_t ntlm_sockets[MAX_EASY_HANDLES]; -+static CURLcode ntlmcb_res = CURLE_OK; - - static size_t callback(char *ptr, size_t size, size_t nmemb, void *data) - { -- ssize_t idx = ((CURL **) data) - easy; -+ ssize_t idx = ((CURL **) data) - ntlm_easy; - curl_socket_t sock; - long longdata; - CURLcode code; - const size_t failure = (size && nmemb) ? 0 : 1; - (void)ptr; - -- counter[idx] += (int)(size * nmemb); -+ ntlm_counter[idx] += (int)(size * nmemb); - - /* Get socket being used for this easy handle, otherwise CURL_SOCKET_BAD */ - CURL_IGNORE_DEPRECATION( -- code = curl_easy_getinfo(easy[idx], CURLINFO_LASTSOCKET, &longdata); -+ code = curl_easy_getinfo(ntlm_easy[idx], CURLINFO_LASTSOCKET, &longdata); - ) - if(CURLE_OK != code) { - fprintf(stderr, "%s:%d curl_easy_getinfo() failed, " - "with code %d (%s)\n", - __FILE__, __LINE__, (int)code, curl_easy_strerror(code)); -- res = TEST_ERR_MAJOR_BAD; -+ ntlmcb_res = TEST_ERR_MAJOR_BAD; - return failure; - } - if(longdata == -1L) -@@ -67,16 +67,16 @@ static size_t callback(char *ptr, size_t size, size_t nmemb, void *data) - - if(sock != CURL_SOCKET_BAD) { - /* Track relationship between this easy handle and the socket. */ -- if(sockets[idx] == CURL_SOCKET_BAD) { -+ if(ntlm_sockets[idx] == CURL_SOCKET_BAD) { - /* An easy handle without previous socket, record the socket. */ -- sockets[idx] = sock; -+ ntlm_sockets[idx] = sock; - } -- else if(sock != sockets[idx]) { -+ else if(sock != ntlm_sockets[idx]) { - /* An easy handle with a socket different to previously - tracked one, log and fail right away. Known bug #37. */ - fprintf(stderr, "Handle %d started on socket %d and moved to %d\n", -- curlx_sztosi(idx), (int)sockets[idx], (int)sock); -- res = TEST_ERR_MAJOR_BAD; -+ curlx_sztosi(idx), (int)ntlm_sockets[idx], (int)sock); -+ ntlmcb_res = TEST_ERR_MAJOR_BAD; - return failure; - } - } -@@ -89,8 +89,9 @@ enum HandleState { - NoMoreHandles - }; - --int test(char *url) -+CURLcode test(char *url) - { -+ CURLcode res = CURLE_OK; - CURLM *multi = NULL; - int running; - int i; -@@ -107,8 +108,8 @@ int test(char *url) - } - - for(i = 0; i < MAX_EASY_HANDLES; ++i) { -- easy[i] = NULL; -- sockets[i] = CURL_SOCKET_BAD; -+ ntlm_easy[i] = NULL; -+ ntlm_sockets[i] = CURL_SOCKET_BAD; - } - - res_global_init(CURL_GLOBAL_ALL); -@@ -130,28 +131,31 @@ int test(char *url) - - /* Start a new handle if we aren't at the max */ - if(state == ReadyForNewHandle) { -- easy_init(easy[num_handles]); -+ easy_init(ntlm_easy[num_handles]); - - if(num_handles % 3 == 2) { - msnprintf(full_url, urllen, "%s0200", url); -- easy_setopt(easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_NTLM); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_NTLM); - } - else { - msnprintf(full_url, urllen, "%s0100", url); -- easy_setopt(easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_BASIC); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - } -- easy_setopt(easy[num_handles], CURLOPT_FRESH_CONNECT, 1L); -- easy_setopt(easy[num_handles], CURLOPT_URL, full_url); -- easy_setopt(easy[num_handles], CURLOPT_VERBOSE, 1L); -- easy_setopt(easy[num_handles], CURLOPT_HTTPGET, 1L); -- easy_setopt(easy[num_handles], CURLOPT_USERPWD, "testuser:testpass"); -- easy_setopt(easy[num_handles], CURLOPT_WRITEFUNCTION, callback); -- easy_setopt(easy[num_handles], CURLOPT_WRITEDATA, easy + num_handles); -- easy_setopt(easy[num_handles], CURLOPT_HEADER, 1L); -- -- multi_add_handle(multi, easy[num_handles]); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_FRESH_CONNECT, 1L); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_URL, full_url); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_VERBOSE, 1L); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_HTTPGET, 1L); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_USERPWD, -+ "testuser:testpass"); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_WRITEFUNCTION, callback); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_WRITEDATA, -+ ntlm_easy + num_handles); -+ easy_setopt(ntlm_easy[num_handles], CURLOPT_HEADER, 1L); -+ -+ multi_add_handle(multi, ntlm_easy[num_handles]); - num_handles += 1; - state = NeedSocketForNewHandle; -+ res = ntlmcb_res; - } - - multi_perform(multi, &running); -@@ -223,9 +227,9 @@ test_cleanup: - /* proper cleanup sequence - type PB */ - - for(i = 0; i < MAX_EASY_HANDLES; i++) { -- printf("Data connection %d: %d\n", i, counter[i]); -- curl_multi_remove_handle(multi, easy[i]); -- curl_easy_cleanup(easy[i]); -+ printf("Data connection %d: %d\n", i, ntlm_counter[i]); -+ curl_multi_remove_handle(multi, ntlm_easy[i]); -+ curl_easy_cleanup(ntlm_easy[i]); - } - - curl_multi_cleanup(multi); -diff --git a/tests/libtest/libprereq.c b/tests/libtest/libprereq.c -index 92369d838..3eef5f369 100644 ---- a/tests/libtest/libprereq.c -+++ b/tests/libtest/libprereq.c -@@ -51,7 +51,7 @@ static int prereq_callback(void *clientp, - return prereq_cb->prereq_retcode; - } - --int test(char *URL) -+CURLcode test(char *URL) - { - PRCS prereq_cb; - CURLcode ret = CURLE_OK; -diff --git a/tests/libtest/mk-lib1521.pl b/tests/libtest/mk-lib1521.pl -index e1418a013..e66887465 100755 ---- a/tests/libtest/mk-lib1521.pl -+++ b/tests/libtest/mk-lib1521.pl -@@ -24,17 +24,162 @@ - ########################################################################### - - # Usage: --# perl mk-lib1521.pl < ../../include/curl/curl.h > lib1521.c -+# perl mk-lib1521.pl < ../../include/curl/curl.h lib1521.c - - # minimum and maximum long signed values - my $minlong = "LONG_MIN"; - my $maxlong = "LONG_MAX"; --# maximum long unsigned value --my $maxulong = "ULONG_MAX"; -+# maximum curl_off_t -+my $maxofft = "CURL_OFF_T_MAX"; - my $line = ""; - my $incomment = 0; - --print <
, et al. -+ * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms -@@ -58,37 +203,22 @@ print <
- - /* This source code is generated by mk-lib1521.pl ! */ - --struct data { -+struct testdata { - char *blaha; - }; - - #define LO $minlong - #define HI $maxlong - #define OFF_LO (curl_off_t) LO --#define OFF_HI (curl_off_t) $maxulong -+#define OFF_HI (curl_off_t) $maxofft - #define OFF_NO (curl_off_t) 0 - --/* Unexpected error. -- CURLE_NOT_BUILT_IN - means disabled at build -- CURLE_UNKNOWN_OPTION - means no such option (anymore?) -- CURLE_SSL_ENGINE_NOTFOUND - set unknown ssl engine -- CURLE_UNSUPPORTED_PROTOCOL - set bad HTTP version -- CURLE_BAD_FUNCTION_ARGUMENT - unsupported value -- */ --#define UNEX(x) ((x) && \\ -- ((x) != CURLE_NOT_BUILT_IN) && \\ -- ((x) != CURLE_UNKNOWN_OPTION) && \\ -- ((x) != CURLE_SSL_ENGINE_NOTFOUND) && \\ -- ((x) != CURLE_UNSUPPORTED_PROTOCOL) && \\ -- ((x) != CURLE_BAD_FUNCTION_ARGUMENT) ) -- - static size_t writecb(char *buffer, size_t size, size_t nitems, - void *outstream) - { -@@ -111,18 +241,44 @@ static size_t readcb(char *buffer, - return 0; - } - --static int err(const char *name, CURLcode val, int lineno) -+static void errlongzero(const char *name, CURLcode code, int lineno) -+{ -+ printf("%s set to 0 returned %d, \\"%s\\" on line %d\\n", -+ name, code, curl_easy_strerror(code), lineno); -+} -+ -+static void errlong(const char *name, CURLcode code, int lineno) -+{ -+$allowednumerrors -+ printf("%s set to non-zero returned %d, \\"%s\\" on line %d\\n", -+ name, code, curl_easy_strerror(code), lineno); -+} -+ -+static void errstring(const char *name, CURLcode code, int lineno) -+{ -+ /* allow this set of options to return CURLE_BAD_FUNCTION_ARGUMENT -+ when given a strange string input */ -+$allowedstringerrors -+ printf("%s set to a string returned %d, \\"%s\\" on line %d\\n", -+ name, code, curl_easy_strerror(code), lineno); -+} -+ -+static void err(const char *name, CURLcode val, int lineno) -+{ -+ printf("%s returned %d, \\"%s\\" on line %d\\n", -+ name, val, curl_easy_strerror(val), lineno); -+} -+ -+static void errnull(const char *name, CURLcode val, int lineno) - { -- printf("CURLOPT_%s returned %d, \\"%s\\" on line %d\\n", -+ printf("%s set to NULL returned %d, \\"%s\\" on line %d\\n", - name, val, curl_easy_strerror(val), lineno); -- return (int)val; - } - --static int geterr(const char *name, CURLcode val, int lineno) -+static void geterr(const char *name, CURLcode val, int lineno) - { - printf("CURLINFO_%s returned %d, \\"%s\\" on line %d\\n", - name, val, curl_easy_strerror(val), lineno); -- return (int)val; - } - - static curl_progress_callback progresscb; -@@ -146,7 +302,30 @@ static curl_hstswrite_callback hstswritecb; - static curl_resolver_start_callback resolver_start_cb; - static curl_prereq_callback prereqcb; - --int test(char *URL) -+/* long options that are okay to return -+ CURLE_BAD_FUNCTION_ARGUMENT */ -+static bool bad_long(CURLcode res, int check) -+{ -+ if(res != CURLE_BAD_FUNCTION_ARGUMENT) -+ return 0; /* not okay */ -+ -+ if(check < CURLOPTTYPE_OBJECTPOINT) { -+ /* LONG */ -+ return 1; -+ } -+ else if((check >= CURLOPTTYPE_OFF_T) && -+ (check < CURLOPTTYPE_BLOB)) { -+ /* OFF_T */ -+ return 1; -+ } -+ return 0; -+} -+ -+/* macro to check the first setopt of an option which then is allowed to get a -+ non-existing function return code back */ -+#define present(x) ((x != CURLE_NOT_BUILT_IN) && (x != CURLE_UNKNOWN_OPTION)) -+ -+CURLcode test(char *URL) - { - CURL *curl = NULL; - CURL *dep = NULL; -@@ -161,7 +340,7 @@ int test(char *URL) - struct curl_httppost *httppost = NULL; - curl_mime *mimepost = NULL; - FILE *stream = stderr; -- struct data object; -+ struct testdata object; - char *charp; - long val; - curl_off_t oval; -@@ -181,6 +360,7 @@ int test(char *URL) - goto test_cleanup; - } - -+ CURL_IGNORE_DEPRECATION( - HEADER - ; - -@@ -235,78 +415,136 @@ while() { - if($_ =~ /^CURLOPT(?:DEPRECATED)?\(([^ ]*), ([^ ]*), (\d*)[,)]/) { - my ($name, $type, $val)=($1, $2, $3); - my $w=" "; -- my $pref = "${w}res = curl_easy_setopt(curl, $name,"; -- my $i = ' ' x (length($w) + 23); -- my $check = " if(UNEX(res)) {\n err(\"$name\", res, __LINE__);\n goto test_cleanup;\n }\n"; -+ my $w2="$w$w"; -+ my $w3="$w$w$w"; -+ my $opt = $name; -+ $opt =~ s/^CURLOPT_//; -+ my $exists = "${w}{\n"; -+ # the first check for an option -+ my $fpref = "${exists}${w2}CURLcode first =\n${w3}curl_easy_setopt(curl, $name,"; -+ my $ifpresent = "${w2}if(present(first)) {\n"; -+ my $pref = "${w3}res = curl_easy_setopt(curl, $name,"; -+ my $i = ' ' x (length($w) + 25); -+ my $fcheck = <) { - ($_ =~ /^CURLINFO_([^ ]*) *= *CURLINFO_([^ ]*)/)) { - my ($info, $type)=($1, $2); - my $c = " res = curl_easy_getinfo(curl, CURLINFO_$info,"; -- my $check = " if(UNEX(res)) {\n geterr(\"$info\", res, __LINE__);\n goto test_cleanup;\n }\n"; -+ my $check = " if(res)\n geterr(\"$info\", res, __LINE__);\n"; - if($type eq "STRING") { -- print "$c &charp);\n$check"; -+ print $fh "$c &charp);\n$check"; - } - elsif($type eq "LONG") { -- print "$c &val);\n$check"; -+ print $fh "$c &val);\n$check"; - } - elsif($type eq "OFF_T") { -- print "$c &oval);\n$check"; -+ print $fh "$c &oval);\n$check"; - } - elsif($type eq "DOUBLE") { -- print "$c &dval);\n$check"; -+ print $fh "$c &dval);\n$check"; - } - elsif($type eq "SLIST") { -- print "$c &slist);\n$check"; -- print " if(slist)\n curl_slist_free_all(slist);\n"; -+ print $fh "$c &slist);\n$check"; -+ print $fh " if(slist)\n curl_slist_free_all(slist);\n"; - } - elsif($type eq "SOCKET") { -- print "$c &sockfd);\n$check"; -+ print $fh "$c &sockfd);\n$check"; - } - elsif($type eq "PTR") { - if($info eq "CERTINFO") { -- print "$c &certinfo);\n$check"; -+ print $fh "$c &certinfo);\n$check"; - } - elsif(($info eq "TLS_SESSION") || - ($info eq "TLS_SSL_PTR")) { -- print "$c &tlssession);\n$check"; -+ print $fh "$c &tlssession);\n$check"; - } - else { - print STDERR "$info/$type is unsupported\n"; -@@ -354,7 +592,8 @@ while() { - } - - --print <