diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml
index 7f1ea5a5eb..b479b46e4c 100644
--- a/.github/workflows/linux.yml
+++ b/.github/workflows/linux.yml
@@ -103,7 +103,12 @@ jobs:
- name: 'mbedtls valgrind'
install_packages: libnghttp2-dev libidn2-dev libldap-dev valgrind
install_steps: mbedtls
- configure: LDFLAGS=-Wl,-rpath,/home/runner/mbedtls/lib --with-mbedtls=/home/runner/mbedtls --enable-debug
+ generate: >-
+ -DCURL_USE_MBEDTLS=ON -DENABLE_DEBUG=ON
+ -DMBEDTLS_INCLUDE_DIR=/home/runner/mbedtls/include
+ -DMBEDTLS_LIBRARY=/home/runner/mbedtls/lib/libmbedtls.a
+ -DMBEDX509_LIBRARY=/home/runner/mbedtls/lib/libmbedx509.a
+ -DMBEDCRYPTO_LIBRARY=/home/runner/mbedtls/lib/libmbedcrypto.a
- name: 'mbedtls clang'
install_packages: libnghttp2-dev libldap-dev clang
@@ -145,7 +150,7 @@ jobs:
- name: 'openssl libssh2 sync-resolver valgrind'
install_packages: zlib1g-dev libidn2-dev libssh2-1-dev libnghttp2-dev libldap-dev valgrind
- configure: --with-openssl --enable-debug --disable-threaded-resolver --with-libssh2
+ generate: -DENABLE_DEBUG=ON -DENABLE_THREADED_RESOLVER=OFF -DCURL_USE_LIBSSH2=ON
- name: 'openssl'
install_packages: zlib1g-dev
@@ -160,7 +165,8 @@ jobs:
- name: 'openssl -O3 libssh valgrind'
install_packages: zlib1g-dev libssh-dev valgrind
- configure: CFLAGS=-O3 --with-openssl --enable-debug --with-libssh
+ CFLAGS: -O3
+ generate: -DENABLE_DEBUG=ON -DCURL_USE_LIBSSH=ON
- name: 'openssl clang krb5 openldap static'
install_steps: openldap-static
@@ -260,12 +266,12 @@ jobs:
- name: 'rustls valgrind'
install_packages: libnghttp2-dev libldap-dev valgrind
install_steps: rust rustls
- configure: --with-rustls --enable-ech --enable-debug
+ generate: -DCURL_USE_RUSTLS=ON -DUSE_ECH=ON -DENABLE_DEBUG=ON
- name: 'rustls'
install_packages: libnghttp2-dev libldap-dev
install_steps: rust rustls skiprun pytest
- generate: -DCURL_USE_RUSTLS=ON -DUSE_ECH=ON -DENABLE_DEBUG=ON
+ configure: --with-rustls --enable-ech --enable-debug
- name: 'IntelC openssl'
install_packages: zlib1g-dev libssl-dev
@@ -700,7 +706,7 @@ jobs:
../.github/scripts/randcurl.pl 60 ../bld/src/curl
- name: 'build examples'
- if: ${{ matrix.build.make-custom-target != 'tidy' }}
+ if: ${{ !contains(matrix.build.install_packages, 'valgrind') && matrix.build.make-custom-target != 'tidy' }}
run: |
if [ "${MATRIX_BUILD}" = 'cmake' ]; then
${MATRIX_MAKE_PREFIX} cmake --build bld --verbose --target curl-examples-build
diff --git a/.github/workflows/non-native.yml b/.github/workflows/non-native.yml
index 91431c922b..c584803fd6 100644
--- a/.github/workflows/non-native.yml
+++ b/.github/workflows/non-native.yml
@@ -248,7 +248,7 @@ jobs:
with:
persist-credentials: false
- name: 'autotools'
- uses: vmactions/omnios-vm@8eba2a9217262f275d4566751a92d6ef2f433d00 # v1
+ uses: vmactions/omnios-vm@c31844c7abe722cd7c97df82cab1f1fab1e5339f # v1
with:
usesh: true
# https://pkg.omnios.org/r151052/core/en/index.shtml
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index f6d029ddb0..af05bb92c8 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -551,7 +551,7 @@ jobs:
- name: 'curl version'
timeout-minutes: 1
run: |
- PATH=/usr/bin find . \( -name '*.exe' -o -name '*.dll' -o -name '*.a' \) -exec file '{}' \;
+ /usr/bin/find . \( -name '*.exe' -o -name '*.dll' -o -name '*.a' \) -exec file '{}' \;
PATH="$PWD/bld/lib:$PATH"
bld/src/curl.exe --disable --version
@@ -821,16 +821,58 @@ jobs:
[ -f "${MINGW_PREFIX}/include/zconf.h" ] && sed -i -E 's|(# +define +Z_HAVE_UNISTD_H)|/*\1*/|g' "${MINGW_PREFIX}/include/zconf.h" # Patch MSYS2 zconf.h for MSVC
for _chkprefill in '' ${MATRIX_CHKPREFILL}; do
options=''
+ cflags=''
+ rcflags=''
+ ldflags=''
if [ "${MATRIX_PLAT}" = 'uwp' ]; then
options+=' -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0'
- cflags='-DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP'
- ldflags='-OPT:NOREF -OPT:NOICF -APPCONTAINER:NO'
+ cflags+=' -DWINAPI_FAMILY=WINAPI_FAMILY_PC_APP'
+ ldflags+=' -OPT:NOREF -OPT:NOICF -APPCONTAINER:NO'
vsglobals=';AppxPackage=false;WindowsAppContainer=false'
fi
- [ "${MATRIX_ARCH}" = 'arm64' ] && options+=' -A ARM64'
- [ "${MATRIX_ARCH}" = 'x64' ] && options+=' -A x64'
- [ "${MATRIX_ARCH}" = 'x86' ] && options+=' -A Win32'
- [ "${TFLAGS}" = 'skiprun' ] && options+=' -D_CURL_SKIP_BUILD_CERTS=ON'
+ if [ "${TFLAGS}" = 'skiprun' ]; then
+ [ "${MATRIX_ARCH}" = 'arm64' ] && options+=' -A ARM64'
+ [ "${MATRIX_ARCH}" = 'x64' ] && options+=' -A x64'
+ [ "${MATRIX_ARCH}" = 'x86' ] && options+=' -A Win32'
+ options+=" -DCMAKE_VS_GLOBALS=TrackFileAccess=false${vsglobals}"
+ options+=' -D_CURL_SKIP_BUILD_CERTS=ON'
+ unset CMAKE_GENERATOR
+ else
+ # Use Ninja when running tests to avoid MSBuild heuristics picking
+ # up "error messages" in the test log output and making the job fail.
+ # Officially this requires the vcvarsall.bat MS-DOS batch file (as of
+ # VS2022). Since it integrates badly with CI steps and shell scripts
+ # scripts, reproduce the necessary build configuration manually, and
+ # without envs.
+ [[ "$(uname -s)" = *'ARM64'* ]] && MSVC_HOST='arm64' || MSVC_HOST='x64' # x86
+ MSVC_ROOTD="$(cygpath --mixed --short-name "$PROGRAMFILES/Microsoft Visual Studio")" # to avoid spaces in directory names
+ MSVC_ROOTU="$(/usr/bin/find "$(cygpath --unix "$MSVC_ROOTD/2022/Enterprise/vc/tools/msvc")" -mindepth 1 -maxdepth 1 -type d -name '*.*' | sort | tail -n 1)"
+ MSVC_ROOTW="$(cygpath --mixed "$MSVC_ROOTU")"
+ MSVC_ROOTU="$(cygpath --unix "$MSVC_ROOTW")"
+ MSVC_BINU="$MSVC_ROOTU/bin/Host$MSVC_HOST/$MATRIX_ARCH"
+ MSDK_ROOTW="$(cygpath --mixed --short-name "$(printenv 'ProgramFiles(x86)')/Windows Kits")/10"
+ MSDK_ROOTU="$(cygpath --unix "$MSDK_ROOTW")"
+ MSDK_VER="$(basename "$(/usr/bin/find "$MSDK_ROOTU/lib" -mindepth 1 -maxdepth 1 -type d -name '*.*' | sort | tail -n 1)")"
+ MSDK_LIBW="$MSDK_ROOTW/lib/$MSDK_VER"
+ MSDK_INCW="$MSDK_ROOTW/include/$MSDK_VER"
+ MSDK_BINU="$MSDK_ROOTU/bin/$MSDK_VER/$MSVC_HOST"
+ cflags+=" -external:W0"
+ cflags+=" -external:I$MSVC_ROOTW/include"
+ cflags+=" -external:I$MSDK_INCW/shared"
+ cflags+=" -external:I$MSDK_INCW/ucrt"
+ cflags+=" -external:I$MSDK_INCW/um"
+ cflags+=" -external:I$MSDK_INCW/km"
+ rcflags+=" -I$MSDK_INCW/shared"
+ rcflags+=" -I$MSDK_INCW/um"
+ ldflags+=" -libpath:$MSVC_ROOTW/lib/$MATRIX_ARCH"
+ ldflags+=" -libpath:$MSDK_LIBW/ucrt/$MATRIX_ARCH"
+ ldflags+=" -libpath:$MSDK_LIBW/um/$MATRIX_ARCH"
+ ldflags+=" -libpath:$MSDK_LIBW/km/$MATRIX_ARCH"
+ options+=" -DCMAKE_RC_COMPILER=$MSDK_BINU/rc.exe"
+ options+=" -DCMAKE_MT=$MSDK_BINU/mt.exe"
+ options+=" -DCMAKE_C_COMPILER=$MSVC_BINU/cl.exe"
+ export CMAKE_GENERATOR='Ninja Multi-Config' # pass it via env to avoid space issues
+ fi
[ "${_chkprefill}" = '_chkprefill' ] && options+=' -D_CURL_PREFILL=OFF'
if [ -n "${MATRIX_INSTALL_VCPKG}" ]; then
options+=" -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
@@ -840,9 +882,9 @@ jobs:
fi
cmake -B "bld${_chkprefill}" ${options} \
-DCMAKE_C_FLAGS="${cflags}" \
+ -DCMAKE_RC_FLAGS="${rcflags}" \
-DCMAKE_EXE_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
-DCMAKE_SHARED_LINKER_FLAGS="-INCREMENTAL:NO ${ldflags}" \
- -DCMAKE_VS_GLOBALS="TrackFileAccess=false${vsglobals}" \
-DCMAKE_UNITY_BUILD=ON \
-DCURL_WERROR=ON \
-DLIBPSL_INCLUDE_DIR="${MINGW_PREFIX}/include" \
@@ -871,7 +913,7 @@ jobs:
- name: 'curl version'
timeout-minutes: 1
run: |
- PATH=/usr/bin find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \;
+ /usr/bin/find . \( -name '*.exe' -o -name '*.dll' -o -name '*.lib' -o -name '*.pdb' \) -exec file '{}' \;
if [ "${MATRIX_PLAT}" != 'uwp' ]; then # Missing: ucrtbased.dll, VCRUNTIME140D.dll, VCRUNTIME140D_APP.dll
PATH="$PWD/bld/lib/${MATRIX_TYPE}:$PATH"
"bld/src/${MATRIX_TYPE}/curl.exe" --disable --version
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 9aa5003d0a..770daed1de 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -3,8 +3,8 @@ curl and libcurl 8.15.1
Public curl releases: 270
Command line options: 272
curl_easy_setopt() options: 308
- Public functions in libcurl: 97
- Contributors: 3486
+ Public functions in libcurl: 98
+ Contributors: 3490
This release includes the following changes:
@@ -15,6 +15,7 @@ This release includes the following changes:
o curl: make --retry-delay and --retry-max-time accept decimal seconds [112]
o hostip: cache negative name resolves [175]
o ip happy eyeballing: keep attempts running [80]
+ o mbedtls: bump minimum version required to 3.2.0 [180]
o multi: add curl_multi_get_offt [56]
o multi: add CURLMOPT_NETWORK_CHANGED to signal network changed [84]
o netrc: use the NETRC environment variable (first) if set [70]
@@ -22,6 +23,7 @@ This release includes the following changes:
o tls: make default TLS version be minimum 1.2 [71]
o tool_getparam: add support for `--longopt=value` [69]
o vquic: drop msh3 [8]
+ o websocket: support CURLOPT_READFUNCTION [193]
o writeout: add %time{} [74]
This release includes the following bugfixes:
@@ -50,6 +52,7 @@ This release includes the following bugfixes:
o cmake: fix `ENABLE_UNIX_SOCKETS=OFF` with pre-fill enabled on unix
o cmake: fix to disable Schannel and SSPI for non-Windows targets
o cmake: fix to restrict `SystemConfiguration` to macOS [139]
+ o cmake: improve error message for invalid HTTP/3 MultiSSL configs [187]
o cmake: keep websockets disabled if HTTP is disabled
o cmake: make `runtests` targets build the curl tool [32]
o cmake: make the ExternalProject test work [183]
@@ -62,6 +65,8 @@ This release includes the following bugfixes:
o connectdata: remove primary+secondary ip_quadruple [126]
o connection: terminate after goaway [62]
o contrithanks: fix for BSD `sed` tool [98]
+ o cookie: don't treat the leading slash as trailing [185]
+ o cookie: remove expired cookies before listing [158]
o curl-config: remove X prefix use [138]
o curl/system.h: fix for GCC 3.3.x and older [38]
o curl: make the URL indexes 64 bit [117]
@@ -84,6 +89,8 @@ This release includes the following bugfixes:
o CURLOPT: bump remaining macros to `long` [147]
o CURLOPT: drop redundant `long` casts [55]
o CURLOPT: replace `(long)` cast with `L` suffix for `CURLHSTS_*` macros
+ o CURLOPT_HTTP_VERSION: mention new default value [179]
+ o CURLOPT_SSL_CTX_*: replace the base64 with XXXX [171]
o delta: fix warnings, fix for non-GNU `date` tool [99]
o DEPRECATE.md: drop support for Windows XP/2003 [31]
o DEPRECATE.md: remove leftover "nothing" [57]
@@ -94,6 +101,8 @@ This release includes the following bugfixes:
o doh: rename symbols to avoid collision with mingw-w64 headers [66]
o easy handle: check validity on external calls [28]
o examples: drop long cast for `CURLALTSVC_*`
+ o examples: remove base64 encoded chunks from examples [189]
+ o examples: remove href_extractor.c [186]
o gnutls: some small cleanups [41]
o hmac: return error if init fails [2]
o hostip: do DNS cache pruning in milliseconds [132]
@@ -109,6 +118,7 @@ This release includes the following bugfixes:
o libtests: update format strings to avoid casts, drop some macros [109]
o libtests: use `FMT_SOCKET_T`, drop more casts [136]
o managen: reset text mode at end of table marker [145]
+ o mbedtls: check for feature macros instead of version [166]
o memanalyze: fix warnings [22]
o memory: make function overrides work reliably in unity builds [93]
o multi event: remove only announced [25]
@@ -119,16 +129,21 @@ This release includes the following bugfixes:
o multi: replace remaining EXPIRE_RUN_NOW [67]
o multissl: initialize when requesting a random number [30]
o ngtcp2: extend callback tables for nghttp3 1.11.0 and ngtcp2 1.14.0 [47]
+ o openssl: auto-pause on verify callback retry [167]
o openssl: check SSL_write() length on retries [152]
o openssl: clear errors after a failed `d2i_X509()` [161]
o openssl: output unescaped utf8 x509 issuer/subject DNs [169]
+ o openssl: save and restore OpenSSL error queue in two functions [172]
o openssl: some small cleanups [42]
o openssl: split cert_stuff into smaller sub functions [72]
o parallel-max: bump the max value to 65535 [86]
+ o processhelp.pm: fix to use the correct null device on Windows [164]
o pytest: add SOCKS tests and scoring [9]
o pytest: increase server KeepAliveTimeout [26]
o pytest: relax error check on test_07_22 [16]
+ o resolving: dns error tracing [196]
o runtests: add `--ci` option, show `Env:` only when non-empty [134]
+ o runtests: assume `Time::HiRes`, drop Perl Win32 dependency [163]
o schannel: add an error message for client cert not found [165]
o schannel: assume `CERT_CHAIN_REVOCATION_CHECK_CHAIN` [114]
o schannel: drop fallbacks for 4 macros [121]
@@ -139,6 +154,7 @@ This release includes the following bugfixes:
o schannel: use if(result) like the code style says [125]
o scripts: enable strict warnings in Perl where missing, fix fallouts [63]
o scripts: fix two Perl uninitialized value warnings [60]
+ o sendf: getting less data than "max allowed" is okay [170]
o servers: convert two macros to scoped static const strings [89]
o setopt: refactor out the booleans from setopt_long to setopt_bool [83]
o setopt: split out cookielist() and cookiefile() [130]
@@ -163,6 +179,7 @@ This release includes the following bugfixes:
o tidy-up: move literal to the right side of comparisons [65]
o tidy-up: prefer `ifdef`/`ifndef` for single checks [64]
o tls: CURLINFO_TLS_SSL_PTR testing [79]
+ o TODO: remove session export item [194]
o tool_cb_wrt: stop alloc/free for every chunk windows console output [140]
o tool_operate: avoid superfluous strdup'ing output [1]
o tool_operate: use the correct config pointer [115]
@@ -171,6 +188,7 @@ This release includes the following bugfixes:
o tool_urlglob: polish, cleanups, improvements [141]
o unit-tests: build the unitprotos.h from here [73]
o unit2604: avoid `UNCONST()` [135]
+ o URL-SYNTAX.md: drop link to codepoints.net to pass linkcheck [190]
o urlapi: allow more path characters "raw" when asked to URL encode [146]
o urldata: reduce two long struct fields to unsigned short [174]
o vquic-tls: fix SSL backend type for QUIC connections using gnutls [29]
@@ -210,16 +228,18 @@ advice from friends like these:
adamse on github, Ahmad Gani, Alice Lee Poetics, Ammar Faizi, Anthony Hu,
Berthin Torres Callañaupa, Caolán McNamara, Cole Leavitt, d1r3ct0r,
- Dan Fandrich, Daniel Böhmer, Daniel Stenberg, David Zhuang, devgs on github,
- Dominik Tomecki, Eshan Kelkar, Harry Sintonen, IoannisGS on github,
- Jeroen Ooms, Kai Pastor, Karthik Das, kkmuffme on github,
+ Dan Fandrich, Daniel Böhmer, Daniel Engberg, Daniel Stenberg, David Zhuang,
+ devgs on github, Dominik Tomecki, Eshan Kelkar, Google Big Sleep,
+ Harry Sintonen, IoannisGS on github, Jelle Raaijmakers, Jeroen Ooms,
+ Kai Pastor, Karthik Das, kkmuffme on github, kupavcevdenis on github,
letshack9707 on hackerone, lf- on github, LoRd_MuldeR, Michał Petryka,
nevakrien on github, Oxan van Leeuwen, Paul Gilmartin, Petar Popovic,
Philippe Antoine, Pino Toscano, Qriist, Qriist on github, Ray Satiro,
- renovate[bot], rm-rmonaghan on github, Roberto Hidalgo, Schrijvers Luc,
- Sergio Durigan Junior, Stefan Eissing, Tal Regev, Todd Gamblin,
- Viktor Szakats, Waldemar Kornewald, yaoy6 on github, ウさん
- (47 contributors)
+ renovate[bot], rm-rmonaghan on github, Roberto Hidalgo, Samuel Henrique,
+ Schrijvers Luc, Sergio Durigan Junior, Stefan Eissing, Tal Regev,
+ Todd Gamblin, Viktor Szakats, Waldemar Kornewald, xfangfang, yaoy6 on github,
+ ウさん
+ (53 contributors)
References to bug reports and discussions on issues:
@@ -379,17 +399,35 @@ References to bug reports and discussions on issues:
[154] = https://curl.se/bug/?i=18241
[155] = https://curl.se/bug/?i=18238
[156] = https://curl.se/bug/?i=18195
+ [158] = https://curl.se/bug/?i=18299
[159] = https://curl.se/bug/?i=18232
[160] = https://curl.se/bug/?i=18177
[161] = https://curl.se/bug/?i=18190
[162] = https://curl.se/bug/?i=18230
+ [163] = https://curl.se/bug/?i=18287
+ [164] = https://curl.se/bug/?i=18282
[165] = https://curl.se/bug/?i=18124
+ [166] = https://curl.se/bug/?i=18271
+ [167] = https://curl.se/mail/lib-2025-08/0012.html
[168] = https://curl.se/bug/?i=18170
[169] = https://curl.se/bug/?i=18171
+ [170] = https://curl.se/bug/?i=18283
+ [171] = https://curl.se/bug/?i=18261
+ [172] = https://curl.se/bug/?i=18190
[173] = https://curl.se/bug/?i=18123
[174] = https://curl.se/bug/?i=18173
[175] = https://curl.se/bug/?i=18157
[176] = https://curl.se/bug/?i=17974
[178] = https://curl.se/bug/?i=18216
+ [179] = https://curl.se/bug/?i=18272
+ [180] = https://curl.se/bug/?i=18254
[183] = https://curl.se/bug/?i=18208
[184] = https://curl.se/bug/?i=18206
+ [185] = https://curl.se/bug/?i=18266
+ [186] = https://curl.se/bug/?i=18264
+ [187] = https://curl.se/bug/?i=18246
+ [189] = https://curl.se/bug/?i=18260
+ [190] = https://curl.se/bug/?i=18259
+ [193] = https://curl.se/bug/?i=17683
+ [194] = https://curl.se/bug/?i=18243
+ [196] = https://curl.se/bug/?i=18247
diff --git a/docs/examples/cacertinmem.c b/docs/examples/cacertinmem.c
index 3a409dc5bd..9b39667aff 100644
--- a/docs/examples/cacertinmem.c
+++ b/docs/examples/cacertinmem.c
@@ -49,22 +49,22 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer)
/* replace the XXX with the actual CA certificates */
static const char mypem[] =
"-----BEGIN CERTIFICATE-----\n"
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END CERTIFICATE-----\n"
"-----BEGIN CERTIFICATE-----\n"
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END CERTIFICATE-----\n";
BIO *cbio = BIO_new_mem_buf(mypem, sizeof(mypem));
diff --git a/docs/examples/usercertinmem.c b/docs/examples/usercertinmem.c
index 49722ca30f..536b65b490 100644
--- a/docs/examples/usercertinmem.c
+++ b/docs/examples/usercertinmem.c
@@ -61,36 +61,36 @@ static CURLcode sslctx_function(CURL *curl, void *sslctx, void *pointer)
const char *mypem =
/* replace the XXX with the actual CA certificate */
- "-----BEGIN CERTIFICATE-----\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
+ "-----BEGIN CERTIFICATE-----\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END CERTIFICATE-----\n";
/* replace the XXX with the actual RSA key */
const char *mykey =
- "-----BEGIN RSA PRIVATE KEY-----\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
- "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END RSA PRIVATE KEY-----\n";
(void)curl; /* avoid warnings */
diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md
index 81edea682d..6dc81a0867 100644
--- a/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md
+++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md
@@ -83,15 +83,14 @@ int main(void)
{
CURL *ch;
CURLcode rv;
- char *mypem = /* example CA cert PEM - shortened */
+ char *mypem = /* CA cert in PEM format, replace the XXXs */
"-----BEGIN CERTIFICATE-----\n"
- "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"
- "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"
- "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"
- "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"
- "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"
- "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"
- "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END CERTIFICATE-----\n";
curl_global_init(CURL_GLOBAL_ALL);
diff --git a/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md
index ebf4c2ec3e..75e1dc8edb 100644
--- a/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md
+++ b/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md
@@ -60,7 +60,9 @@ callbacks to add additional validation code for certificates, and even to
change the actual URI of an HTTPS request.
For OpenSSL, asynchronous certificate verification via *SSL_set_retry_verify*
-is supported. (Added in 8.3.0)
+is supported. When *SSL_set_retry_verify* is set, the transfer is paused.
+When verification should continue, call curl_easy_pause(3) to unpause
+the transfer. (Added in 8.3.0, Pausing added in 8.16.0)
The CURLOPT_SSL_CTX_FUNCTION(3) callback allows the application to reach in
and modify SSL details in the connection without libcurl itself knowing
@@ -134,15 +136,14 @@ int main(void)
{
CURL *ch;
CURLcode rv;
- char *mypem = /* example CA cert PEM - shortened */
+ char *mypem = /* CA cert in PEM format, replace the XXXs */
"-----BEGIN CERTIFICATE-----\n"
- "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"
- "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"
- "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"
- "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"
- "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"
- "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"
- "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"
"-----END CERTIFICATE-----\n";
curl_global_init(CURL_GLOBAL_ALL);
diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c
index 509ec427a8..7884dc166a 100644
--- a/lib/asyn-thrdd.c
+++ b/lib/asyn-thrdd.c
@@ -655,12 +655,9 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
return result;
#ifndef CURL_DISABLE_SOCKETPAIR
- if(thrdd->addr) {
- /* return read fd to client for polling the DNS resolution status */
- result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
- }
- else
-#endif
+ /* return read fd to client for polling the DNS resolution status */
+ result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
+#else
{
timediff_t milli;
timediff_t ms = curlx_timediff(curlx_now(), thrdd->addr->start);
@@ -674,7 +671,7 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
}
-
+#endif
return result;
}
diff --git a/lib/bufq.c b/lib/bufq.c
index 9919707b4c..c97640a63c 100644
--- a/lib/bufq.c
+++ b/lib/bufq.c
@@ -537,7 +537,8 @@ CURLcode Curl_bufq_write_pass(struct bufq *q,
if(result != CURLE_AGAIN)
/* real error, fail */
return result;
- if((result == CURLE_AGAIN) && *pwritten)
+ /* result == CURLE_AGAIN */
+ if(*pwritten)
/* we did write successfully before */
result = CURLE_OK;
return result;
diff --git a/lib/cookie.c b/lib/cookie.c
index b72dd99bce..99b5e43d64 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -1615,6 +1615,9 @@ static struct curl_slist *cookie_list(struct Curl_easy *data)
if(!data->cookies || (data->cookies->numcookies == 0))
return NULL;
+ /* at first, remove expired cookies */
+ remove_expired(data->cookies);
+
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
for(n = Curl_llist_head(&data->cookies->cookielist[i]); n;
n = Curl_node_next(n)) {
diff --git a/lib/ftp.c b/lib/ftp.c
index f088054b2d..dde651a53e 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1256,7 +1256,7 @@ out:
!Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
}
- data->conn->bits.do_more = FALSE;
+ conn->bits.do_more = FALSE;
Curl_pgrsTime(data, TIMER_STARTACCEPT);
Curl_expire(data, (data->set.accepttimeout > 0) ?
data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
diff --git a/lib/multi.c b/lib/multi.c
index d38155cd9b..1c09b14b6b 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1026,9 +1026,13 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data,
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
- result = mstate_connecting_pollset(data, ps);
- if(!result)
- result = Curl_conn_adjust_pollset(data, data->conn, ps);
+ if(!Curl_xfer_recv_is_paused(data)) {
+ result = mstate_connecting_pollset(data, ps);
+ if(!result)
+ result = Curl_conn_adjust_pollset(data, data->conn, ps);
+ }
+ else
+ expect_sockets = FALSE;
break;
case MSTATE_PROTOCONNECT:
@@ -2434,22 +2438,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
- result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
- if(connected && !result) {
- if(!data->conn->bits.reuse &&
- Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
- /* new connection, can multiplex, wake pending handles */
- process_pending_handles(data->multi);
+ if(!Curl_xfer_recv_is_paused(data)) {
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
+ if(connected && !result) {
+ if(!data->conn->bits.reuse &&
+ Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
+ /* new connection, can multiplex, wake pending handles */
+ process_pending_handles(data->multi);
+ }
+ rc = CURLM_CALL_MULTI_PERFORM;
+ multistate(data, MSTATE_PROTOCONNECT);
+ }
+ else if(result) {
+ /* failure detected */
+ multi_posttransfer(data);
+ multi_done(data, result, TRUE);
+ stream_error = TRUE;
+ break;
}
- rc = CURLM_CALL_MULTI_PERFORM;
- multistate(data, MSTATE_PROTOCONNECT);
- }
- else if(result) {
- /* failure detected */
- multi_posttransfer(data);
- multi_done(data, result, TRUE);
- stream_error = TRUE;
- break;
}
break;
diff --git a/lib/sendf.c b/lib/sendf.c
index 6bd4b1bfba..43b30ecc7f 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -293,9 +293,9 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
if((type & CLIENTWRITE_EOS) && !data->req.no_body &&
- (data->req.maxdownload > data->req.bytecount)) {
+ (data->req.size > data->req.bytecount)) {
failf(data, "end of response with %" FMT_OFF_T " bytes missing",
- data->req.maxdownload - data->req.bytecount);
+ data->req.size - data->req.bytecount);
return CURLE_PARTIAL_FILE;
}
}
diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c
index 6467025137..575ebb9022 100644
--- a/lib/vquic/curl_ngtcp2.c
+++ b/lib/vquic/curl_ngtcp2.c
@@ -1212,7 +1212,7 @@ static CURLcode init_ngh3_conn(struct Curl_cfilter *cf,
rc = nghttp3_conn_client_new(&ctx->h3conn,
&ngh3_callbacks,
&ctx->h3settings,
- nghttp3_mem_default(),
+ Curl_nghttp3_mem(),
cf);
if(rc) {
failf(data, "error creating nghttp3 connection instance");
@@ -2475,7 +2475,7 @@ static const struct alpn_spec ALPN_SPEC_H3 = {
&ctx->connected_path,
NGTCP2_PROTO_VER_V1, &ng_callbacks,
&ctx->settings, &ctx->transport_params,
- NULL, cf);
+ Curl_ngtcp2_mem(), cf);
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c
index fa2c0a2899..3dd9753a72 100644
--- a/lib/vquic/curl_osslq.c
+++ b/lib/vquic/curl_osslq.c
@@ -1106,7 +1106,7 @@ static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn,
rc = nghttp3_conn_client_new(&h3->conn,
&ngh3_callbacks,
&h3->settings,
- nghttp3_mem_default(),
+ Curl_nghttp3_mem(),
user_data);
if(rc) {
result = CURLE_OUT_OF_MEMORY;
diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c
index f8ce34129b..43a2c95021 100644
--- a/lib/vquic/vquic.c
+++ b/lib/vquic/vquic.c
@@ -724,6 +724,62 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_OK;
}
+#if defined(USE_NGTCP2) || defined(USE_NGHTTP3)
+
+static void *Curl_ngtcp2_malloc(size_t size, void *user_data)
+{
+ (void)user_data;
+ return Curl_cmalloc(size);
+}
+
+static void Curl_ngtcp2_free(void *ptr, void *user_data)
+{
+ (void)user_data;
+ Curl_cfree(ptr);
+}
+
+static void *Curl_ngtcp2_calloc(size_t nmemb, size_t size, void *user_data)
+{
+ (void)user_data;
+ return Curl_ccalloc(nmemb, size);
+}
+
+static void *Curl_ngtcp2_realloc(void *ptr, size_t size, void *user_data)
+{
+ (void)user_data;
+ return Curl_crealloc(ptr, size);
+}
+
+#ifdef USE_NGTCP2
+static struct ngtcp2_mem curl_ngtcp2_mem = {
+ NULL,
+ Curl_ngtcp2_malloc,
+ Curl_ngtcp2_free,
+ Curl_ngtcp2_calloc,
+ Curl_ngtcp2_realloc
+};
+struct ngtcp2_mem *Curl_ngtcp2_mem(void)
+{
+ return &curl_ngtcp2_mem;
+}
+#endif
+
+#ifdef USE_NGHTTP3
+static struct nghttp3_mem curl_nghttp3_mem = {
+ NULL,
+ Curl_ngtcp2_malloc,
+ Curl_ngtcp2_free,
+ Curl_ngtcp2_calloc,
+ Curl_ngtcp2_realloc
+};
+struct nghttp3_mem *Curl_nghttp3_mem(void)
+{
+ return &curl_nghttp3_mem;
+}
+#endif
+
+#endif /* USE_NGTCP2 || USE_NGHTTP3 */
+
#else /* CURL_DISABLE_HTTP || !USE_HTTP3 */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
diff --git a/lib/vquic/vquic_int.h b/lib/vquic/vquic_int.h
index d271368d29..38189beb70 100644
--- a/lib/vquic/vquic_int.h
+++ b/lib/vquic/vquic_int.h
@@ -91,4 +91,13 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
#endif /* !USE_HTTP3 */
+#ifdef USE_NGTCP2
+struct ngtcp2_mem;
+struct ngtcp2_mem *Curl_ngtcp2_mem(void);
+#endif
+#ifdef USE_NGHTTP3
+struct nghttp3_mem;
+struct nghttp3_mem *Curl_nghttp3_mem(void);
+#endif
+
#endif /* HEADER_CURL_VQUIC_QUIC_INT_H */
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index c4c2981108..e25c57304d 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -61,6 +61,7 @@
#include "../vauth/vauth.h"
#include "keylog.h"
#include "hostcheck.h"
+#include "../transfer.h"
#include "../multiif.h"
#include "../curlx/strparse.h"
#include "../strdup.h"
@@ -4602,7 +4603,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ Curl_xfer_pause_recv(data, TRUE);
return CURLE_AGAIN;
}
#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 014fe0db87..0593b513ee 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -104,6 +104,7 @@ if(MSVC OR CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Cl
if(APPLE AND CMAKE_OSX_SYSROOT)
string(APPEND CURL_CPP " -isysroot ${CMAKE_OSX_SYSROOT}")
endif()
+ string(APPEND CURL_CPP " ${CMAKE_C_FLAGS}")
# Add header directories, like autotools builds do.
get_property(_include_dirs TARGET ${LIB_SELECTED} PROPERTY INCLUDE_DIRECTORIES)
foreach(_include_dir IN LISTS _include_dirs)
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 1c0258e17c..71fc94860d 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -108,7 +108,7 @@ 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 test743 test744 \
test745 test746 test747 test748 test749 test750 test751 test752 test753 \
-test754 test755 test756 test757 \
+test754 test755 test756 test757 test758 \
test780 test781 test782 test783 test784 test785 test786 test787 test788 \
test789 test790 test791 test792 test793 test794 test796 test797 \
\
@@ -203,11 +203,11 @@ 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 test1547 \
-test1548 \
-test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
-test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
-test1566 test1567 test1568 test1569 test1570 test1571 test1572 test1573 \
-test1574 test1575 test1576 test1577 test1578 test1579 test1580 test1581 \
+test1548 test1549 test1550 test1551 test1552 test1553 test1554 test1555 \
+test1556 test1557 test1558 test1559 test1560 test1561 test1562 test1563 \
+test1564 test1565 test1566 test1567 test1568 test1569 test1570 test1571 \
+test1572 test1573 test1574 test1575 test1576 test1577 test1578 test1579 \
+test1580 test1581 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 test1599 test1600 test1601 test1602 test1603 test1604 test1605 \
@@ -256,8 +256,8 @@ test2100 test2101 test2102 test2103 test2104 \
\
test2200 test2201 test2202 test2203 test2204 test2205 \
\
-test2300 test2301 test2302 test2303 test2304 test2306 \
-test2308 test2309 \
+test2300 test2301 test2302 test2303 test2304 test2306 test2307 test2308 \
+test2309 \
\
test2400 test2401 test2402 test2403 test2404 test2405 test2406 \
\
diff --git a/tests/data/test1549 b/tests/data/test1549
new file mode 100644
index 0000000000..bc821e5eba
--- /dev/null
+++ b/tests/data/test1549
@@ -0,0 +1,59 @@
+
+
+
+HTTP
+cookies
+
+
+
+#
+# Server-side
+
+
+HTTP/1.1 200 OK
+Content-Length: 6
+Content-Type: text/plain
+Set-Cookie: c1=123; Path=/; Expires=Thu, 12 Feb 2000 00:00:00 GMT
+Set-Cookie: c2=456; Path=/; Expires=Thu, 12 Feb 2000 00:00:00 GMT;
+
+hello
+
+
+
+#
+# Client-side
+
+
+http
+
+
+http
+cookies
+
+
+Receive expired cookies and CURLINFO_COOKIELIST
+
+
+lib%TESTNUMBER
+
+
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+
+
+
+#
+# Verify data after the test has been "shot"
+
+
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+
+
+URL: http://%HOSTIP:%HTTPPORT/%TESTNUMBER
+0 cookies
+Test ended with result 0
+
+
+
diff --git a/tests/data/test2307 b/tests/data/test2307
new file mode 100644
index 0000000000..cbb581a4ab
--- /dev/null
+++ b/tests/data/test2307
@@ -0,0 +1,60 @@
+
+
+
+FTP
+EPSV
+RETR
+Range
+
+
+# Server-side
+
+
+0123456789abcdef
+0123456789abcdef
+0123456789abcdef
+0123456789abcdef
+
+
+0123456789abcdef
+0123456789abcdef
+0123456789abcdef
+012345678
+
+
+64
+
+
+
+# Client-side
+
+
+ftp
+
+
+FTP retrieve a byte-range with end larger than file
+
+
+-r 4-1000 ftp://%HOSTIP:%FTPPORT/%TESTNUMBER
+
+
+
+# Verify data after the test has been "shot"
+
+
+QUIT
+
+
+USER anonymous
+PASS ftp@example.com
+PWD
+EPSV
+TYPE I
+SIZE %TESTNUMBER
+REST 4
+RETR %TESTNUMBER
+ABOR
+QUIT
+
+
+
diff --git a/tests/data/test758 b/tests/data/test758
new file mode 100644
index 0000000000..a807ae9c85
--- /dev/null
+++ b/tests/data/test758
@@ -0,0 +1,53 @@
+
+
+
+multi
+HTTPS
+
+
+
+# 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]%
+
+
+
+
+OpenSSL
+
+
+# Client-side
+
+
+https
+
+
+lib%TESTNUMBER
+
+
+multi_socket interface transfer with callbacks returning error
+
+
+https://localhost:%HTTPSPORT/file%TESTNUMBER
+
+
+
+# Verify data after the test has been "shot"
+
+
+
+
+
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 5e14621087..40ec0d1559 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -71,7 +71,7 @@ TESTS_C = \
lib661.c lib666.c lib667.c lib668.c \
lib670.c lib674.c lib676.c lib677.c lib678.c \
lib694.c lib695.c \
- lib751.c lib753.c \
+ lib751.c lib753.c lib758.c \
lib757.c \
lib1156.c \
lib1301.c lib1308.c \
@@ -82,7 +82,7 @@ TESTS_C = \
lib1522.c lib1523.c lib1525.c lib1526.c lib1527.c lib1528.c \
lib1529.c lib1530.c lib1531.c lib1532.c lib1533.c lib1534.c lib1535.c \
lib1536.c lib1537.c lib1538.c lib1540.c lib1541.c lib1542.c \
- lib1545.c lib1550.c lib1551.c \
+ lib1545.c lib1549.c lib1550.c lib1551.c \
lib1552.c lib1553.c lib1554.c lib1555.c lib1556.c lib1557.c lib1558.c \
lib1559.c lib1560.c lib1564.c lib1565.c \
lib1567.c lib1568.c lib1569.c lib1571.c \
diff --git a/tests/libtest/lib1549.c b/tests/libtest/lib1549.c
new file mode 100644
index 0000000000..b7bf010612
--- /dev/null
+++ b/tests/libtest/lib1549.c
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "first.h"
+
+#include "testtrace.h"
+#include "memdebug.h"
+
+static CURLcode test_lib1549(const char *URL)
+{
+ CURLcode res;
+ CURL *curl;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ curl_mfprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ curl = curl_easy_init();
+ if(!curl) {
+ curl_mfprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ test_setopt(curl, CURLOPT_URL, URL);
+ test_setopt(curl, CURLOPT_HEADER, 1L);
+ test_setopt(curl, CURLOPT_COOKIEFILE, "");
+
+ res = curl_easy_perform(curl);
+
+ if(!res) {
+ /* extract all known cookies */
+ struct curl_slist *cookies = NULL;
+ int num = 0;
+ res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
+ if(!res && cookies) {
+ /* a linked list of cookies in cookie file format */
+ struct curl_slist *each = cookies;
+ while(each) {
+ printf("%s\n", each->data);
+ each = each->next;
+ num++;
+ }
+ /* we must free these cookies when we are done */
+ curl_slist_free_all(cookies);
+ }
+ fprintf(stderr, "%d cookies\n", num);
+ }
+test_cleanup:
+
+ curl_easy_cleanup(curl);
+ curl_global_cleanup();
+
+ return res;
+}
diff --git a/tests/libtest/lib758.c b/tests/libtest/lib758.c
new file mode 100644
index 0000000000..dfcbaebb31
--- /dev/null
+++ b/tests/libtest/lib758.c
@@ -0,0 +1,515 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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
+ *
+ ***************************************************************************/
+
+/*
+ * The purpose of this test is to make sure that if CURLMOPT_SOCKETFUNCTION or
+ * CURLMOPT_TIMERFUNCTION returns error, the associated transfer should be
+ * aborted correctly.
+ */
+
+#include "first.h"
+
+#include "testtrace.h"
+#include "memdebug.h"
+
+#ifdef USE_OPENSSL
+
+#include
+#include
+
+#if ((OPENSSL_VERSION_NUMBER >= 0x30000000L) && \
+ !defined(LIBRESSL_VERSION_NUMBER) && \
+ !defined(OPENSSL_IS_BORINGSSL))
+#define T578_ENABLED
+#endif
+#endif
+
+#ifdef T578_ENABLED
+
+static struct t758_ctx {
+ int socket_calls;
+ int max_socket_calls;
+ int timer_calls;
+ int max_timer_calls;
+ int fake_async_cert_verification_pending;
+ int fake_async_cert_verification_finished;
+ int number_of_cert_verify_callbacks;
+ char buf[1024];
+} t758_ctx;
+
+static const char *t758_tag(void)
+{
+ curl_msnprintf(t758_ctx.buf, sizeof(t758_ctx.buf),
+ "[T758-%d-%d] [%d/%d]",
+ t758_ctx.max_socket_calls, t758_ctx.max_timer_calls,
+ t758_ctx.socket_calls, t758_ctx.timer_calls);
+ return t758_ctx.buf;
+}
+
+static void t758_msg(const char *msg)
+{
+ curl_mfprintf(stderr, "%s %s\n", t758_tag(), msg);
+}
+
+
+struct t758_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 t758_ReadWriteSockets {
+ struct t758_Sockets read, write;
+};
+
+/**
+ * Remove a file descriptor from a sockets array.
+ */
+static void t758_removeFd(struct t758_Sockets *sockets, curl_socket_t fd,
+ int mention)
+{
+ int i;
+
+ if(mention)
+ curl_mfprintf(stderr, "%s remove socket fd %" FMT_SOCKET_T "\n",
+ t758_tag(), fd);
+
+ for(i = 0; i < sockets->count; ++i) {
+ if(sockets->sockets[i] == fd) {
+ if(i < sockets->count - 1)
+ memmove(&sockets->sockets[i], &sockets->sockets[i + 1],
+ sizeof(curl_socket_t) * (sockets->count - (i + 1)));
+ --sockets->count;
+ }
+ }
+}
+
+/**
+ * Add a file descriptor to a sockets array.
+ * Return 0 on success, 1 on error.
+ */
+static int t758_addFd(struct t758_Sockets *sockets, curl_socket_t fd,
+ const char *what)
+{
+ /**
+ * To ensure we only have each file descriptor once, we remove it then add
+ * it again.
+ */
+ curl_mfprintf(stderr, "%s add socket fd %" FMT_SOCKET_T " for %s\n",
+ t758_tag(), fd, what);
+ t758_removeFd(sockets, fd, 0);
+ /*
+ * Allocate array storage when required.
+ */
+ if(!sockets->sockets) {
+ sockets->sockets = malloc(sizeof(curl_socket_t) * 20U);
+ if(!sockets->sockets)
+ return 1;
+ sockets->max_count = 20;
+ }
+ else if(sockets->count + 1 > sockets->max_count) {
+ curl_socket_t *ptr = realloc(sockets->sockets, sizeof(curl_socket_t) *
+ (sockets->max_count + 20));
+ if(!ptr)
+ /* cleanup in test_cleanup */
+ return 1;
+ sockets->sockets = ptr;
+ sockets->max_count += 20;
+ }
+ /*
+ * Add file descriptor to array.
+ */
+ sockets->sockets[sockets->count] = fd;
+ ++sockets->count;
+ return 0;
+}
+
+/**
+ * Callback invoked by curl to poll reading / writing of a socket.
+ */
+static int t758_curlSocketCallback(CURL *easy, curl_socket_t s, int action,
+ void *userp, void *socketp)
+{
+ struct t758_ReadWriteSockets *sockets = userp;
+
+ (void)easy;
+ (void)socketp;
+
+ t758_ctx.socket_calls++;
+ t758_msg("-> CURLMOPT_SOCKETFUNCTION");
+ if(t758_ctx.socket_calls == t758_ctx.max_socket_calls) {
+ t758_msg("<- CURLMOPT_SOCKETFUNCTION returns error");
+ return -1;
+ }
+
+ if(action == CURL_POLL_IN || action == CURL_POLL_INOUT)
+ if(t758_addFd(&sockets->read, s, "read"))
+ return -1; /* bail out */
+
+ if(action == CURL_POLL_OUT || action == CURL_POLL_INOUT)
+ if(t758_addFd(&sockets->write, s, "write"))
+ return -1;
+
+ if(action == CURL_POLL_REMOVE) {
+ t758_removeFd(&sockets->read, s, 1);
+ t758_removeFd(&sockets->write, s, 0);
+ }
+
+ return 0;
+}
+
+/**
+ * Callback invoked by curl to set a timeout.
+ */
+static int t758_curlTimerCallback(CURLM *multi, long timeout_ms, void *userp)
+{
+ struct curltime *timeout = userp;
+
+ (void)multi; /* unused */
+ t758_ctx.timer_calls++;
+ t758_msg("-> CURLMOPT_TIMERFUNCTION");
+ if(t758_ctx.timer_calls == t758_ctx.max_timer_calls) {
+ t758_msg("<- CURLMOPT_TIMERFUNCTION returns error");
+ return -1;
+ }
+ if(timeout_ms != -1) {
+ *timeout = curlx_now();
+ timeout->tv_usec += (int)timeout_ms * 1000;
+ }
+ else {
+ timeout->tv_sec = -1;
+ }
+ return 0;
+}
+
+static int t758_cert_verify_callback(X509_STORE_CTX *ctx, void *arg)
+{
+ SSL * ssl;
+ (void)arg; /* unused */
+ ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ t758_ctx.number_of_cert_verify_callbacks++;
+ if(!t758_ctx.fake_async_cert_verification_pending) {
+ t758_ctx.fake_async_cert_verification_pending = 1;
+ t758_msg(" initial t758_cert_verify_callback");
+ return SSL_set_retry_verify(ssl);
+ }
+ else if(t758_ctx.fake_async_cert_verification_finished) {
+ t758_msg(" final t758_cert_verify_callback");
+ return 1; /* success */
+ }
+ else {
+ t758_msg(" pending t758_cert_verify_callback");
+ return SSL_set_retry_verify(ssl);
+ }
+}
+
+static CURLcode
+t758_set_ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *clientp)
+{
+ SSL_CTX *ctx = (SSL_CTX *) ssl_ctx;
+ (void)curl; /* unused */
+ SSL_CTX_set_cert_verify_callback(ctx, t758_cert_verify_callback, clientp);
+ return CURLE_OK;
+}
+
+/**
+ * Check for curl completion.
+ */
+static int t758_checkForCompletion(CURLM *curl, int *success)
+{
+ int result = 0;
+ *success = 0;
+ while(1) {
+ int numMessages;
+ CURLMsg *message = curl_multi_info_read(curl, &numMessages);
+ if(!message)
+ break;
+ if(message->msg == CURLMSG_DONE) {
+ result = 1;
+ if(message->data.result == CURLE_OK)
+ *success = 1;
+ else
+ *success = 0;
+ }
+ else {
+ curl_mfprintf(stderr, "%s got an unexpected message from curl: %i\n",
+ t758_tag(), message->msg);
+ result = 1;
+ *success = 0;
+ }
+ }
+ return result;
+}
+
+static ssize_t t758_getMicroSecondTimeout(struct curltime *timeout)
+{
+ struct curltime now;
+ ssize_t result;
+ now = curlx_now();
+ result = (ssize_t)((timeout->tv_sec - now.tv_sec) * 1000000 +
+ timeout->tv_usec - now.tv_usec);
+ if(result < 0)
+ result = 0;
+
+ return result;
+}
+
+/**
+ * Update a fd_set with all of the sockets in use.
+ */
+static void t758_updateFdSet(struct t758_Sockets *sockets, fd_set* fdset,
+ curl_socket_t *maxFd)
+{
+ int i;
+ for(i = 0; i < sockets->count; ++i) {
+#ifdef __DJGPP__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warith-conversion"
+#endif
+ FD_SET(sockets->sockets[i], fdset);
+#ifdef __DJGPP__
+#pragma GCC diagnostic pop
+#endif
+ if(*maxFd < sockets->sockets[i] + 1) {
+ *maxFd = sockets->sockets[i] + 1;
+ }
+ }
+}
+
+static CURLMcode t758_saction(CURLM *curl, curl_socket_t s,
+ int evBitmask, const char *info)
+{
+ int numhandles = 0;
+ CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles);
+ if(result != CURLM_OK) {
+ curl_mfprintf(stderr, "%s Curl error on %s (%i) %s\n",
+ t758_tag(), info, result, curl_multi_strerror(result));
+ }
+ return result;
+}
+
+/**
+ * Invoke curl when a file descriptor is set.
+ */
+static CURLMcode t758_checkFdSet(CURLM *curl, struct t758_Sockets *sockets,
+ fd_set *fdset, int evBitmask,
+ const char *name)
+{
+ int i;
+ CURLMcode result = CURLM_OK;
+ for(i = 0; i < sockets->count; ++i) {
+ if(FD_ISSET(sockets->sockets[i], fdset)) {
+ result = t758_saction(curl, sockets->sockets[i], evBitmask, name);
+ if(result)
+ break;
+ }
+ }
+ return result;
+}
+
+static CURLcode t758_one(const char *URL, int timer_fail_at,
+ int socket_fail_at)
+{
+ CURLcode res = CURLE_OK;
+ CURL *curl = NULL; CURLM *m = NULL;
+ struct t758_ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}};
+ int success = 0;
+ struct curltime timeout = {0};
+ timeout.tv_sec = (time_t)-1;
+
+ /* set the limits */
+ memset(&t758_ctx, 0, sizeof(t758_ctx));
+ t758_ctx.max_timer_calls = timer_fail_at;
+ t758_ctx.max_socket_calls = socket_fail_at;
+
+ t758_msg("start");
+ start_test_timing();
+
+ if(curl_global_sslset(CURLSSLBACKEND_OPENSSL, NULL, NULL) != CURLSSLSET_OK) {
+ t758_msg("could not set OpenSSL as backend");
+ res = CURLE_FAILED_INIT;
+ return res;
+ }
+
+ res_global_init(CURL_GLOBAL_ALL);
+ if(res != CURLE_OK)
+ return res;
+
+ curl_global_trace("all");
+
+
+ easy_init(curl);
+ debug_config.nohex = TRUE;
+ debug_config.tracetime = TRUE;
+ test_setopt(curl, CURLOPT_DEBUGDATA, &debug_config);
+ easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
+ easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ /* specify target */
+ easy_setopt(curl, CURLOPT_URL, URL);
+
+ /* go verbose */
+ easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, t758_set_ssl_ctx_callback);
+
+ multi_init(m);
+
+ multi_setopt(m, CURLMOPT_SOCKETFUNCTION, t758_curlSocketCallback);
+ multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets);
+
+ multi_setopt(m, CURLMOPT_TIMERFUNCTION, t758_curlTimerCallback);
+ multi_setopt(m, CURLMOPT_TIMERDATA, &timeout);
+
+ multi_add_handle(m, curl);
+
+ if(t758_saction(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) {
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ while(!t758_checkForCompletion(m, &success)) {
+ fd_set readSet, writeSet;
+ curl_socket_t maxFd = 0;
+ struct timeval tv = {0};
+ tv.tv_sec = 10;
+
+ if(t758_ctx.fake_async_cert_verification_pending &&
+ !t758_ctx.fake_async_cert_verification_finished) {
+ if(sockets.read.count || sockets.write.count) {
+ t758_msg("during verification there should be no sockets scheduled");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ if(t758_ctx.number_of_cert_verify_callbacks != 1) {
+ t758_msg("expecting exactly one cert verify callback here");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ t758_ctx.fake_async_cert_verification_finished = 1;
+ if(t758_saction(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) {
+ t758_msg("spurious retry cert action");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ curl_easy_pause(curl, CURLPAUSE_CONT);
+ if(t758_saction(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) {
+ t758_msg("unblocking transfer after cert verification finished");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ if(t758_ctx.number_of_cert_verify_callbacks != 2) {
+ t758_msg("this should have triggered the callback again, right?");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ t758_msg("TEST: all fine?");
+ }
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ t758_updateFdSet(&sockets.read, &readSet, &maxFd);
+ t758_updateFdSet(&sockets.write, &writeSet, &maxFd);
+
+ if(timeout.tv_sec != (time_t)-1) {
+ int usTimeout = curlx_sztosi(t758_getMicroSecondTimeout(&timeout));
+ tv.tv_sec = usTimeout / 1000000;
+ tv.tv_usec = usTimeout % 1000000;
+ }
+ else if(maxFd <= 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ }
+
+ select_test((int)maxFd, &readSet, &writeSet, NULL, &tv);
+
+ /* Check the sockets for reading / writing */
+ if(t758_checkFdSet(m, &sockets.read, &readSet, CURL_CSELECT_IN,
+ "read")) {
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+ if(t758_checkFdSet(m, &sockets.write, &writeSet, CURL_CSELECT_OUT,
+ "write")) {
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+
+ if(timeout.tv_sec != (time_t)-1 &&
+ t758_getMicroSecondTimeout(&timeout) == 0) {
+ /* Curl's timer has elapsed. */
+ if(t758_saction(m, CURL_SOCKET_TIMEOUT, 0, "timeout")) {
+ res = TEST_ERR_BAD_TIMEOUT;
+ goto test_cleanup;
+ }
+ }
+
+ abort_on_test_timeout();
+ }
+ if(success && t758_ctx.number_of_cert_verify_callbacks != 2) {
+ t758_msg("unexpected invocations of cert verify callback");
+ res = TEST_ERR_MAJOR_BAD;
+ goto test_cleanup;
+ }
+
+ if(!success) {
+ t758_msg("Error getting file.");
+ res = TEST_ERR_MAJOR_BAD;
+ }
+
+test_cleanup:
+
+ /* proper cleanup sequence */
+ t758_msg("cleanup");
+ curl_multi_remove_handle(m, curl);
+ curl_easy_cleanup(curl);
+ curl_multi_cleanup(m);
+ curl_global_cleanup();
+
+ /* free local memory */
+ free(sockets.read.sockets);
+ free(sockets.write.sockets);
+ t758_msg("done");
+
+ return res;
+}
+
+static CURLcode test_lib758(const char *URL)
+{
+ CURLcode rc;
+ /* rerun the same transfer multiple times and make it fail in different
+ callback calls */
+ rc = t758_one(URL, 0, 0); /* no callback fails */
+ if(rc)
+ curl_mfprintf(stderr, "%s FAILED: %d\n", t758_tag(), rc);
+
+ return rc;
+}
+
+#else /* T578_ENABLED */
+static CURLcode test_lib758(const char *URL)
+{
+ (void)URL;
+ return CURLE_OK;
+}
+#endif