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